Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

batch sync events based on event beats #47147

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/react-native/React/Fabric/AppleEventBeat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ namespace facebook::react {
AppleEventBeat::AppleEventBeat(
std::shared_ptr<OwnerBox> ownerBox,
std::unique_ptr<const RunLoopObserver> uiRunLoopObserver,
RuntimeExecutor runtimeExecutor)
: EventBeat(std::move(ownerBox), std::move(runtimeExecutor)),
RuntimeScheduler& runtimeScheduler)
: EventBeat(std::move(ownerBox), runtimeScheduler),
uiRunLoopObserver_(std::move(uiRunLoopObserver)) {
uiRunLoopObserver_->setDelegate(this);
uiRunLoopObserver_->enable();
Expand Down
4 changes: 3 additions & 1 deletion packages/react-native/React/Fabric/AppleEventBeat.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

namespace facebook::react {

class RuntimeScheduler;

/*
* Event beat associated with JavaScript runtime.
* The beat is called on `RuntimeExecutor`'s thread induced by the UI thread
Expand All @@ -23,7 +25,7 @@ class AppleEventBeat : public EventBeat, public RunLoopObserver::Delegate {
AppleEventBeat(
std::shared_ptr<OwnerBox> ownerBox,
std::unique_ptr<const RunLoopObserver> uiRunLoopObserver,
RuntimeExecutor runtimeExecutor);
RuntimeScheduler& RuntimeScheduler);

#pragma mark - RunLoopObserver::Delegate

Expand Down
4 changes: 2 additions & 2 deletions packages/react-native/React/Fabric/RCTSurfacePresenter.mm
Original file line number Diff line number Diff line change
Expand Up @@ -258,10 +258,10 @@ - (RCTScheduler *)_createScheduler
toolbox.bridgelessBindingsExecutor = _bridgelessBindingsExecutor;

toolbox.eventBeatFactory =
[runtimeExecutor](std::shared_ptr<EventBeat::OwnerBox> ownerBox) -> std::unique_ptr<EventBeat> {
[runtimeScheduler](std::shared_ptr<EventBeat::OwnerBox> ownerBox) -> std::unique_ptr<EventBeat> {
auto runLoopObserver =
std::make_unique<const MainRunLoopObserver>(RunLoopObserver::Activity::BeforeWaiting, ownerBox->owner);
return std::make_unique<AppleEventBeat>(std::move(ownerBox), std::move(runLoopObserver), runtimeExecutor);
return std::make_unique<AppleEventBeat>(std::move(ownerBox), std::move(runLoopObserver), *runtimeScheduler);
};

RCTScheduler *scheduler = [[RCTScheduler alloc] initWithToolbox:toolbox];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ namespace facebook::react {
AndroidEventBeat::AndroidEventBeat(
std::shared_ptr<OwnerBox> ownerBox,
EventBeatManager* eventBeatManager,
RuntimeExecutor runtimeExecutor,
RuntimeScheduler& runtimeScheduler,
jni::global_ref<jobject> javaUIManager)
: EventBeat(std::move(ownerBox), std::move(runtimeExecutor)),
: EventBeat(std::move(ownerBox), runtimeScheduler),
eventBeatManager_(eventBeatManager),
javaUIManager_(std::move(javaUIManager)) {
eventBeatManager->addObserver(*this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class AndroidEventBeat final : public EventBeat,
AndroidEventBeat(
std::shared_ptr<OwnerBox> ownerBox,
EventBeatManager* eventBeatManager,
RuntimeExecutor runtimeExecutor,
RuntimeScheduler& runtimeScheduler,
jni::global_ref<jobject> javaUIManager);

~AndroidEventBeat() override;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -471,28 +471,25 @@ void FabricUIManagerBinding::installFabricUIManager(

auto runtimeExecutor = runtimeExecutorHolder->cthis()->get();

if (runtimeSchedulerHolder) {
auto runtimeScheduler = runtimeSchedulerHolder->cthis()->get().lock();
if (runtimeScheduler) {
runtimeExecutor =
[runtimeScheduler](
std::function<void(jsi::Runtime & runtime)>&& callback) {
runtimeScheduler->scheduleWork(std::move(callback));
};
contextContainer->insert(
"RuntimeScheduler",
std::weak_ptr<RuntimeScheduler>(runtimeScheduler));
}
auto runtimeScheduler = runtimeSchedulerHolder->cthis()->get().lock();
if (runtimeScheduler) {
runtimeExecutor =
[runtimeScheduler](
std::function<void(jsi::Runtime & runtime)>&& callback) {
runtimeScheduler->scheduleWork(std::move(callback));
};
contextContainer->insert(
"RuntimeScheduler", std::weak_ptr<RuntimeScheduler>(runtimeScheduler));
}

EventBeat::Factory eventBeatFactory =
[eventBeatManager, runtimeExecutor, globalJavaUiManager](
[eventBeatManager, &runtimeScheduler, globalJavaUiManager](
std::shared_ptr<EventBeat::OwnerBox> ownerBox)
-> std::unique_ptr<EventBeat> {
return std::make_unique<AndroidEventBeat>(
std::move(ownerBox),
eventBeatManager,
runtimeExecutor,
*runtimeScheduler,
globalJavaUiManager);
};

Expand Down
41 changes: 27 additions & 14 deletions packages/react-native/ReactCommon/react/renderer/core/EventBeat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,25 @@

#include "EventBeat.h"

#include <react/renderer/runtimescheduler/RuntimeScheduler.h>
#include <utility>

namespace facebook::react {

EventBeat::EventBeat(
std::shared_ptr<OwnerBox> ownerBox,
RuntimeExecutor runtimeExecutor)
: ownerBox_(std::move(ownerBox)),
runtimeExecutor_(std::move(runtimeExecutor)) {}
RuntimeScheduler& runtimeScheduler)
: ownerBox_(std::move(ownerBox)), runtimeScheduler_(runtimeScheduler) {}

void EventBeat::request() const {
isRequested_ = true;
}

void EventBeat::requestSynchronous() const {
isSynchronousRequested_ = true;
request();
}

void EventBeat::setBeatCallback(BeatCallback beatCallback) {
beatCallback_ = std::move(beatCallback);
}
Expand All @@ -33,17 +38,25 @@ void EventBeat::induce() const {
isRequested_ = false;
isBeatCallbackScheduled_ = true;

runtimeExecutor_([this, ownerBox = ownerBox_](jsi::Runtime& runtime) {
auto owner = ownerBox->owner.lock();
if (!owner) {
return;
}

isBeatCallbackScheduled_ = false;
if (beatCallback_) {
beatCallback_(runtime);
}
});
auto beat = std::function<void(jsi::Runtime&)>(
[this, ownerBox = ownerBox_](jsi::Runtime& runtime) {
auto owner = ownerBox->owner.lock();
if (!owner) {
return;
}

isBeatCallbackScheduled_ = false;
if (beatCallback_) {
beatCallback_(runtime);
}
});

if (isSynchronousRequested_) {
isSynchronousRequested_ = false;
runtimeScheduler_.executeNowOnTheSameThread(std::move(beat));
} else {
runtimeScheduler_.scheduleWork(std::move(beat));
}
}

} // namespace facebook::react
16 changes: 13 additions & 3 deletions packages/react-native/ReactCommon/react/renderer/core/EventBeat.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@

#pragma once

#include <ReactCommon/RuntimeExecutor.h>
#include <atomic>
#include <functional>
#include <memory>

namespace facebook::react {
class RuntimeScheduler;
}

namespace facebook::jsi {
class Runtime;
}
Expand Down Expand Up @@ -56,7 +59,7 @@ class EventBeat {

explicit EventBeat(
std::shared_ptr<OwnerBox> ownerBox,
RuntimeExecutor runtimeExecutor);
RuntimeScheduler& runtimeScheduler);

virtual ~EventBeat() = default;

Expand All @@ -71,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.
*/
Expand All @@ -88,8 +97,9 @@ class EventBeat {
mutable std::atomic<bool> isRequested_{false};

private:
RuntimeExecutor runtimeExecutor_;
RuntimeScheduler& runtimeScheduler_;
mutable std::atomic<bool> isBeatCallbackScheduled_{false};
mutable std::atomic<bool> isSynchronousRequested_{false};
};

} // namespace facebook::react
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,9 @@ namespace facebook::react {
EventDispatcher::EventDispatcher(
const EventQueueProcessor& eventProcessor,
std::unique_ptr<EventBeat> eventBeat,
RuntimeScheduler& runtimeScheduler,
StatePipe statePipe,
std::weak_ptr<EventLogger> eventLogger)
: eventQueue_(
EventQueue(eventProcessor, std::move(eventBeat), runtimeScheduler)),
: eventQueue_(EventQueue(eventProcessor, std::move(eventBeat))),
statePipe_(std::move(statePipe)),
eventLogger_(std::move(eventLogger)) {}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ class EventDispatcher {
EventDispatcher(
const EventQueueProcessor& eventProcessor,
std::unique_ptr<EventBeat> eventBeat,
RuntimeScheduler& runtimeScheduler,
StatePipe statePipe,
std::weak_ptr<EventLogger> eventLogger);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,9 @@ namespace facebook::react {

EventQueue::EventQueue(
EventQueueProcessor eventProcessor,
std::unique_ptr<EventBeat> eventBeat,
RuntimeScheduler& runtimeScheduler)
std::unique_ptr<EventBeat> eventBeat)
: eventProcessor_(std::move(eventProcessor)),
eventBeat_(std::move(eventBeat)),
runtimeScheduler_(&runtimeScheduler) {
eventBeat_(std::move(eventBeat)) {
eventBeat_->setBeatCallback(
[this](jsi::Runtime& runtime) { onBeat(runtime); });
}
Expand Down Expand Up @@ -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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ class EventQueue {
public:
EventQueue(
EventQueueProcessor eventProcessor,
std::unique_ptr<EventBeat> eventBeat,
RuntimeScheduler& runtimeScheduler);
std::unique_ptr<EventBeat> eventBeat);

/*
* Enqueues and (probably later) dispatch a given event.
Expand Down Expand Up @@ -75,10 +74,6 @@ class EventQueue {
mutable std::vector<RawEvent> eventQueue_;
mutable std::vector<StateUpdate> stateUpdateQueue_;
mutable std::mutex queueMutex_;

// TODO: T183075253
RuntimeScheduler* runtimeScheduler_;
mutable std::atomic_bool synchronousAccessRequested_{false};
};

} // namespace facebook::react
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@ Scheduler::Scheduler(
EventQueueProcessor(
eventPipe, eventPipeConclusion, statePipe, eventPerformanceLogger_),
std::move(eventBeat),
*runtimeScheduler,
statePipe,
eventPerformanceLogger_);

Expand Down
Loading