Skip to content

Skip copying the culling context in the differ when view culling is off - #59677

Merged
meta-codesync[bot] merged 1 commit into
react:mainfrom
hryhoriiK97:differ-skip-culling-context-copies
Nov 2, 2026
Merged

meta-codesync[bot] merged 1 commit into
react:mainfrom
hryhoriiK97:differ-skip-culling-context-copies

Conversation

@hryhoriiK97

Copy link
Copy Markdown
Contributor

Summary:

In its two per-child loops (slicing a node's children, and walking matched child pairs), the differ calls CullingContext::adjustCullingContextIfNeeded for every child and reads ReactNativeFeatureFlags::enableViewCulling() each time. Each call builds a ShadowViewNodePair with a copy of the child's ShadowView (props, state and event emitter shared_ptrs) and returns a new CullingContext (a Rect and a Transform with its operations vector). Without view culling, the result is always an unchanged copy of the parent's context.

View culling is off by default, so every commit pays for this on every child the differ visits. This change reads the flag once per call and, when culling is off, passes the parent's context to the children instead. With culling on, the same calls run in the same order as before. The other adjustCullingContextIfNeeded calls are in rarer paths (flattening, unflattening, deletions) and are left as they are.

I found this while profiling typing in a TextInput on Android: each keystroke commits a state update, and the differ walks the whole screen. On a low-end phone the copies were about 5% of the differ's time.

Changelog:

[GENERAL] [CHANGED] - The differ no longer copies its view culling context for every child when view culling is off

Test Plan:

  • yarn fantom with the tester rebuilt from this change:
    • ScrollView-viewCulling-itest.js (runs with enableViewCulling:true): 44 passed.
    • TextInput suites 39 passed, ScrollView suites 86 passed, Mounting-itest.js 56 passed.
    • Full suite: 3316 passed. The other failures are not related to this change: snapshot printing in my checkout's Jest setup (LogBox and expect snapshots), and the known flaky tester crash in one suite (polyfillArrayES2023Methods-itest.js), which passes on rerun.
  • clang-format clean (node scripts/clang-format.js --check).
  • On a device. RNTester release build on a Galaxy A16 (Android 16), one APK with both versions behind a local switch, typing into a TextInput on the TextInput example page for 12 s per run, call stacks sampled at 1 kHz, 5 rounds alternating old/new. JS thread samples spent in adjustCullingContextIfNeeded and the flag reads:
before this PR
per 12 s run 13 / 9 / 12 / 12 / 12 2 / 1 / 1 / 2 / 0

That is about 1.3–1.5% of the JS thread while typing (the differ itself is about 30% of it). Total differ time moves by more than that between runs, so I am not claiming more.

🤖 Generated with Claude Code

Slicing and the differ's matched-pairs loop read `enableViewCulling` and
copy a `CullingContext` (a `Rect` and a `Transform`) for every child, but
without view culling `adjustCullingContextIfNeeded` returns an unchanged
copy. Read the flag once per call and, when culling is off, pass the
parent's context to the children instead of copying it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Oct 30, 2026
@facebook-github-tools facebook-github-tools Bot added p: Software Mansion Partner: Software Mansion Partner Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team. labels Oct 30, 2026
@meta-codesync

meta-codesync Bot commented Oct 30, 2026

Copy link
Copy Markdown

@javache has imported this pull request. If you are a Meta employee, you can view this in D128599926.

@christophpurrer christophpurrer left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review automatically exported from Phabricator review in Meta.

@meta-codesync
meta-codesync Bot merged commit 7230b63 into react:main Nov 2, 2026
107 checks passed
@react-native-bot

Copy link
Copy Markdown
Collaborator

This pull request was successfully merged by @hryhoriiK97 in 7230b63

When will my fix make it into a release? | How to file a pick request?

@react-native-bot react-native-bot added the Merged This PR has been merged. label Nov 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Merged This PR has been merged. p: Software Mansion Partner: Software Mansion Partner Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants