Summary:
Due to the way we're dispatching queued MountItems on Android, we could be doing nothing on the UI thread for up to 15.99...ms before the start of the next frame, resulting in a delayed paint of up to 1 full (16ms) frame.
The delay is totally random and depends only on when the work is scheduled.
The tl;dr is that currently all MountItems are dispatched starting only at the /beginning/ of a UI frame. If we schedule work at FrameStart+0.000001ms, it will not be operated on until the start of the next frame, 16ms later. So the "wasted" time could be anywhere from 0 to ~16ms, but will result in at least 1 wasted frame regardless.
The fix is fairly trivial: start working on large buffered work as soon as we schedule it.
Changelog: [Android][Changed] Optimization to paint changes up to 1 frame earlier on Android/Fabric
Reviewed By: NickGerleman
Differential Revision: D37478885
fbshipit-source-id: 8af846736caf3a9d9f0d0c5e33328bebb87b1b32
Summary:
TL;DR: For applications using JS navigation, save 50-95% of CPU during mounting phase in N>2 navigations that replace ~most of screen.
During investigation of performance on the UI thread of React Native applications, I noticed that the /initial/ render of an screen for an application using JS navigation is /mostly/ consumed (on the UI thread) by tearing-down the previous View hierarchy. In one 185ms segment on the UI thread in production, 95% of the CPU time was Remove/Delete instructions and only 5% of CPU time was consumed by actually displaying the new hierarchy (this is specific to Android and also assumes that View Preallocation is being used, so post-commit work consists of Insert and UpdateLayout mutations primarily).
There are /some/ cases where the C++ differ knows that we are deleting an entire subtree and therefore we could communicate this to the mounting layer. All that matters is that these Views are removed from the View hierarchy immediately; and secondarily that their memory is cleaned up ASAP, but that doesn't need to happen immediately.
Some additional constraints and notes:
1) As noted in the comments, we cannot simply stop producing Remove and Delete instructions. We need to produce /both/ the new RemoveDeleteTree instruction, /and/ produce all the Remove/Delete instructions, primarily because LayoutAnimations relies heavily on these Remove/Delete instructions and certain things would break if we removed those instructions entirely. However, we can mark those Remove/Delete instructions as redundant, process them only in LayoutAnimations, and not send them to the Android mounting layer.
2) We want to make sure that View Recycling is not impacted. Since Android cannot take advantage of View Recycling until /after/ the second major render (preallocation of views will happen before any views are recycled), this doesn't impact View Recycling and we'll make sure Views are recycled whenever they are deleted.
Thus, we do two things:
1) Introduce a new RemoveDeleteTree operation that can delete an entire subtree recursively as part of one operation. This allows us to avoid serializing hundreds or thousands of instructions and prevents JNI traffic.
2) Besides removing the topmost View from the View hierarchy, and ensuring it's not drawn, the full teardown and recycling of the tree can happen /after/ the paint.
In some flows with JS navigation this saves us 95% of CPU during the mount phase. In the general case it is probably closer to 25-50% of CPU time that is saved and/or deferred.
Changelog: [Android][Changed] Significant perf optimization to Fabric Remove/Delete operations
Reviewed By: ryancat
Differential Revision: D37257864
fbshipit-source-id: a7d33fc74683939965cfb98be4db7890644110b2
Summary:
Adding a flag to prepare for the phase 3 of the new architecture. This is still work in progress, not usable yet.
Changelog: [Internal]
Reviewed By: RSNara
Differential Revision: D36767843
fbshipit-source-id: 338d775681f2890461608b403749c3a7f05f84ff
Summary:
There's no need for this to be a setter/getter, as there are no side-effects, and it means we can use the same helper method to read it as other feature flags.
Changelog: [Internal]
Reviewed By: cortinico
Differential Revision: D36595602
fbshipit-source-id: d27c01bd39d03606a6f8c17ba181a8cd0bf58dbb
Summary:
Enables two new experiments (and the current behaviour as default) to speed up access to TurboModule methods from JS.
1) HostObject - Current behaviour
2) Prototype - Connect the TM HostObject via `__proto__`, and cache any methods accessed on the wrapper object.
3) Eager - Eagerly store all methods on the wrapper object, do not expose the HostObject to JS at all (TurboModules no longer need to be HostObjects in this scenario)
Changelog: [Internal]
Reviewed By: JoshuaGross, rubennorte, mdvacca
Differential Revision: D36590018
fbshipit-source-id: c9565eb239eb6aeee0f06b581ff8cd72a92073fc
Summary:
This diff fixed an edge case that event dispatching is failed after pre-allocation of a view and before the view is mounted.
When a cached image is loaded, we will dispatch the event to JS immediately. This is could happen after the view is created during pre-allocation phase, when the event emitter is not instantiated yet. In that case, we will see [an error](https://github.com/facebook/react-native/blob/main/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java#L927) and the event will effectively be ignored.
To fix that we introduced a queue in this diff for those events. They will be dispatched in order when the view is mounted and the event emitter is non-null.
Changelog:
[Android][Fixed] - Fixed an edge case that event dispatching is failed after pre-allocation of a view and before the view is mounted.
Reviewed By: mullender
Differential Revision: D36331914
fbshipit-source-id: cd065b0b36978cb5f0aac793d8d16f07a48f0881
Summary: There's no need to use private feature flag for overflowInset feature. This makes future refactor on feature flags easier.
Reviewed By: javache
Differential Revision: D35866302
fbshipit-source-id: a3fde212ff40cd6d4c68832bb39b34de5a17a8d4
Summary:
Now that the PFH node has been renamed this updates the pfh label.
Produced via `xbgs -l -e '"pfh:ReactNative_CommonInfrastructurePlaceholde"' | xargs sed -i 's/"pfh:ReactNative_CommonInfrastructurePlaceholde"/"pfh:ReactNative_CommonInfrastructurePlaceholder"/'`
Reviewed By: jkeljo
Differential Revision: D35374087
fbshipit-source-id: 61590f69de5a69ec3b8a0478f6dd43409de3c70b
Summary:
While it would be better to be able to do all of the ownership metadata at the Buck macro level, that proved to be more work than expected.
This diff adds the corresponding pfh label to all targets in `xplat/js/react-native-github` that have a Supermodule label. Once the migration is complete the Supermodules labels will be able to be removed.
Reviewed By: cortinico
Differential Revision: D35221544
fbshipit-source-id: d87d5e266dfb5e6ee087251dc34dff5db299bbaf
Summary:
sSpannableCache is a significant user of Java heap memory - up to 0.22MB is retained by sSpannableCache.
It turns out sSpannableCache was never hitting as hashCode is different for the same attributedString contents. attributedString.getInt("hash") provides the expected hash code.
This indicates removing spannableCache will not affect perf. Will gate just in case though.
Changelog: [Internal]
Reviewed By: mdvacca
Differential Revision: D34900414
fbshipit-source-id: 7563cde6ba9dc153072e7aebede99389ce3153e7
Summary:
Blocks on queue write/drain for Animated module under a feature flag to test whether it resolves race conditions.
Changelog: [Internal]
Reviewed By: mdvacca
Differential Revision: D34752947
fbshipit-source-id: a1b1a286772d29a7a27b5e9c3f743cac84cc2bab
Summary:
changelog: [internal]
ViewState is sometimes deleted but not created again because of race condition in C++ pre-allocation and how it checks for revision to determine if createView mount item should be dispatched.
In this diff, we add an option to delay deletion of ViewState until the next commit.
Reviewed By: ShikaSD
Differential Revision: D34553174
fbshipit-source-id: e5213f1d39137fb56fc745321a7c1b28d417ea27
Summary:
Changelog: [Internal]
Remove all the MCs that enable SVCs in Fabric, because we'll only test SVCs in Bridgeless mode to simplify rollout. There were complications with enabling SVCs in Fabric at a previous rollout.
Reviewed By: RSNara
Differential Revision: D33861243
fbshipit-source-id: fdbfedce77f8bd1bab2a807237017787ae8bf7c1
Summary:
This diff deletes the flag ReactFeatureFlags.enableReactContextCleanupFix, the flag was disabled for many months, I just disable it.
changelog: [internal] internal
Reviewed By: genkikondo, makovkastar
Differential Revision: D33781628
fbshipit-source-id: 4b5e22adf9d30da5b85bbbde8bdc98d98f5e8891
Summary:
This diff deletes the ReactFeatureFlag enableFabricInLogBox, from now on Logbox will be rendered in Fabric when Fabric is enabled
changelog: [internal] internal
Reviewed By: genkikondo
Differential Revision: D33781626
fbshipit-source-id: 3187a22fec80125afd27860995637564640dab8d
Summary:
Enable eager intialization of FabricUIManager during intiialization of React Native.
This feature highly improved TTRC in Markeptlace Home
changelog: [internal] internal
Reviewed By: genkikondo
Differential Revision: D33585099
fbshipit-source-id: 0ffbc720bcb1edd1b04180189a52c82e9e2fa800
Summary:
The previous diff shows how `overflowInset` could improve hit test algorithm performance. This diff adds experiment to it in order to:
1. Understand the perf improvement in production
2. Provide quick way to rollback in production -- the changes are used by FB4A as well as VR
3. The changes will pass more instructions over JNI, which may have impact on perf.
To share the MC param values in both Java and C++ side, the value is hosted by `ReactFeatureFlags` and fetched in `FbReactInstanceHolder`.
Changelog: [Internal]
Reviewed By: mdvacca
Differential Revision: D33179310
fbshipit-source-id: 327100d41f7b5a668ff0d2afabcdd1fc16cb5a18
Summary:
With the updates to touch processing rolled out, we can remove the feature flag and clean up the old code. The old path is now used exclusively by legacy renderer and Fabric uses new `EventEmitter#receiveTouches` method to process touches.
Changelog:
[Changed][Android] - Update touch processing internals
Reviewed By: mdvacca
Differential Revision: D32953664
fbshipit-source-id: 517a4ce6ce9bc15528c2db94d7d11bdff8b78743
Summary:
Originally introduced in D2022018
Tried to make the processor optional when no rounding is required, but found even that was not strictly necessary.
Changelog: [Internal]
Reviewed By: mdvacca
Differential Revision: D32675492
fbshipit-source-id: 8dfdbf0e4347155045f77b1fba00a59086fe7a33
Summary:
Changelog: [Internal]
# Context
Whilst looking at Marketplace Loom traces, ShikaSD made the remark that we could potentially start the JS work much earlier instead of waiting for the View.onMeasure call, a behaviour that is already built-in Venice.
Reviewed By: ShikaSD
Differential Revision: D32559505
fbshipit-source-id: cc6337955ad2b6a6581a0347f1f976679eaca54d
Summary:
This bug is caused by RNAndroid dispatching an incorrect sequence of events to JS when the user taps on a Text.
Taking into consideration the example P462662009, when the user taps of the "Inner" text, RN Android is dispatching three events:
topTouchStart, topTouchStart and topTouchEnd.
The information stored on the first two JS events is correct, but the problem is that it is duplicated. This sequence of events makes Pressability to dispatch the event to the incorrect target.
This was originally introduced in D3035589 (https://github.com/facebook/react-native/commit/39fdce259dd46de8fd715efbfd12ede4bc24c8c2) (2016)
In this diff I'm changing the way RN Android bubbles events when the user taps on a ReactTextView. From now on, events won't be bubbled anymore, and they will be handled by the ReactRootView.onInterceptTouchEvent: https://fburl.com/code/rbt8$
Additionally, I'm creating a FeatureFlag in case this change has a unknown side effect that's only detected in production.
I will create a MC for FB4A in the next diffs of the stack
changelog: [Fixed][Android] Fix onPress event for nested Text in RN Android
Reviewed By: javache
Differential Revision: D31628461
fbshipit-source-id: 177397d4369191a3c97e2f86e801757b27ee5121
Summary:
Updates touch events in Fabric to be dispatched through the same pipeline as the rest of events, instead of relying on custom dispatch behavior.
Previous method of handling touches was reusing Paper behavior which required:
1. Transform event into a Paper-compatible form of WritableArray and dispatch it to `RCTEventEmitter.receiveTouches`.
2. Intercept `receiveTouches` for Fabric and redirect it to `FabricEventEmitter`
3. Perform transformations copied from Paper JS renderer in Java, transform it to the final form and dispatch this event as usual after.
The new behavior uses emitter's `receiveEvent` method directly to dispatch events. Additionally, it should decrease allocations done when transforming events during step 3 above, as `WritableNativeMap`-based operations performed many re-allocations when reading/re-creating arrays.
Changelog:
[Android][Changed] - Added an experimental touch dispatch path
Reviewed By: JoshuaGross
Differential Revision: D31280052
fbshipit-source-id: 829c2646ac6b0ebff0f0106159e76d84324ac732
Summary:
Event merging or "coalescing" is done on Java side from Android, but Fabric also includes some Cxx logic to merge those events. Although Android doesn't need this logic in particular, it is important to follow this path to ensure these events (e.g. scroll) are dispatched as "continuous", allowing for correct prioritization in Concurrent Mode.
`dispatchModernV2` selects between `dispatch` and `dispatchUnique` based on the `canBeCoalesced` parameter of the event, which is exactly what we need. The logic is only used in the "new" event dispatcher at the moment, so I wrapped it with feature flag to validate it doesn't cause any regressions.
Changelog:
[Android][Internal] - Try dispatching coalescing events as unique to Fabric
Reviewed By: sammy-SC
Differential Revision: D31272585
fbshipit-source-id: 6b67b61bd13fbff019d9eb8c5172bdd814a7b5b8
Summary:
Uses `enableZ` trick to ensure that Skia doesn't try to reorder the views based on elevation. Unfortunately, it only helps for some cases, but the proper fix would require reimplementing `ViewGroup` completely to remove its internal logic of reordering based on Z coordinate.
Changelog: [Android][Fixed] Ensure elevated views are behind sticky header in FlatList
Reviewed By: cortinico
Differential Revision: D30700566
fbshipit-source-id: d2c59b22332922c610f4f2d415df34e81f5a33c5
Summary:
When true, this flag will cause React Native to start logging soft exceptions, whenever the legacy NativeModule system is used. This flag is independent of useTurboModules. In practice, it's only enabled when TurboModules is enabled.
Changelog: [Internal]
Reviewed By: JoshuaGross
Differential Revision: D30250363
fbshipit-source-id: f610567c5b99a4fbf8252c3962908668f483d028
Summary:
This is the Android analogue to D30019833.
Changelog: [Internal]
Reviewed By: p-sun
Differential Revision: D30029295
fbshipit-source-id: 13df0dfb915697eeedcc527dcdb6c246e89afb0c
Summary:
As a followup to T91209139, ship "state update scroll race" in code. This also ships it for HorizontalScrollView since it's been validated for vertical scroll views.
Changelog: [Internal]
Reviewed By: sammy-SC
Differential Revision: D29595601
fbshipit-source-id: 64b6a23e2dab2c13123e132d9d899fb769d03172
Summary:
Changelog: [internal]
Reland of D29131766 (https://github.com/facebook/react-native/commit/18165367b0347fc46cd52a6ac00afcf62d05cb30) which had to reverted because it caused binary size regression in instagram.
Size check for `automation_instagram_stablesize_release` and `automation_igtv_release`
{F626711916}
Reviewed By: JoshuaGross
Differential Revision: D29263302
fbshipit-source-id: cc8f5609ebaed9ddf666f7c57cdbf3dbf77a8f78
Summary:
Because of T92179998, T93607943, and T93394807, we are still seeking resolution to tricky crashes wrt the use of EventEmitters.
I believe the recent spike is because of two recent changes: we pass in EventEmitters earlier, during PreAllocation; and we clean them up earlier, during stopSurface, to avoid jsi::~Pointer crashes.
Additionally, the gating previously added around the PreAllocation path was incorrect and led to more nullptrs being passed around as EventEmitters.
To mitigate these issues:
1) I am adding/fixing gating to preallocation and early cleanup paths
2) I am making EventEmitterWrapper more resilient by ensuring EventEmitter is non-null before invoking it.
3) I am making sure that in more cases, we pass a non-null EventEmitter pointer to Java.
4) I am backing out the synchronization in EventEmitterWrapper (java side) as that did not resolve the issue and is a pessimisation
There are older, unchanged paths that could still be passing in nullptr as the EventEmitter (Update and Create). As those have not changed recently, I'm not going to fix those cases and instead, we can now rely on the caller to ensure that the EventEmitter is non-null before calling.
Changelog: [internal]
Differential Revision: D29252806
fbshipit-source-id: 5c68d95fa2465afe45e0083a0685c8c1abf31619