[0.85] Backport performance debugging improvements#56637
Open
motiz88 wants to merge 14 commits intofacebook:0.85-stablefrom
Open
[0.85] Backport performance debugging improvements#56637motiz88 wants to merge 14 commits intofacebook:0.85-stablefrom
motiz88 wants to merge 14 commits intofacebook:0.85-stablefrom
Conversation
Summary: Pull Request resolved: facebook#55873 Move `base64Encode` implementation (originally vendored in D58323859) into `ReactCommon/react/utils/` for reuse in other C++ packages. Changelog: [Internal] Reviewed By: cipolleschi Differential Revision: D95041544 fbshipit-source-id: d71376d03079a8cc4d0a6c3652c40d73374858ea
Summary: Pull Request resolved: facebook#55803 Refactor Android FrameTimings to reduce memory usage in trace buffer. Binary data instead of Base64 should be ~25% smaller, and eliminates string copies during JNI transfer. Changelog: [Internal] Reviewed By: rubennorte Differential Revision: D94657907 fbshipit-source-id: c4a183ff00c519fd1545992340fd445530abab99
…ook#55935) Summary: Pull Request resolved: facebook#55935 Changelog: [internal] This diff adds helper functions to the PerformanceTracer class for tracing performance events in React Native Developer Tools traces. In Kotlin, new `trace` method overloads are added to `PerformanceTracer` that wrap a block of code and automatically measure and report its execution time. These use a try/finally pattern to ensure timing is captured correctly. In C++, a new `PerformanceTracerSection` RAII class is added that automatically reports timing when the section goes out of scope. It supports optional track, track group, and color parameters, as well as variadic key-value properties for additional metadata. Reviewed By: sammy-SC Differential Revision: D92061513 fbshipit-source-id: 92c745426c6a9e3a2eee1e85e2a2d7fd12d88ef6
…book#55941) Summary: Pull Request resolved: facebook#55941 Replaces the previous `globalThis.enableTimelineFrames` setup with backend gating. Enables us to: - Iterate more safely by gating Android/iOS/C++ code - Have a per-app rollout at Meta Changelog: [Internal] Reviewed By: vzaidman Differential Revision: D95405444 fbshipit-source-id: 0c41f10059b28ed940a12a44707946baa310bdfb
Summary: Pull Request resolved: facebook#56015 Implements CDP support for the Chrome DevTools Frames track on iOS during a performance trace, including screenshot capture. This initial version matches the corresponding implementation for Android: - Captures the key window. - Always emits an initial frame. - Resizes screenshots at 0.75 scale factor (normalized for device screen DPI) and 80% JPEG compression. - Uses a background thread queue for image resizing. **To dos** - [ ] Emit frames only when there is a visual update. - [ ] Dynamic frame sampling on slower devices (planned for Android). **Limitations** - Not a true screen recording, uses `UIGraphicsImageRenderer`. - Requires no permission prompt ✅ - This can mean empty data (a black screen) is sent during states such as system alert dialogs being presented. - Like Android, if the background queue builds (on slower hardware), screenshot data can be lost when the recording is ended. This feature is gated behind the `fuseboxFrameRecordingEnabled` flag. Changelog: [Internal] Reviewed By: sbuggay Differential Revision: D95566220 fbshipit-source-id: c87f1b6d8334b45e2eb67334a5f0f924d20901ec
Summary: Pull Request resolved: facebook#56043 Use pixel hash comparison to avoid encoding duplicate screenshots on iOS, reducing overhead when frames don't change. Matches Android behaviour. - Samples every 64th pixel with a fast FNV-1a hash (~0.1ms on main thread). - Skips JPEG encoding and CDP transport entirely for unchanged frames — the dominant per-frame cost. **Why this approach** Attempted `CATransaction` completion blocks, however these fire on commits that produce no visual change. No other public API on iOS. Changelog: [Internal] Reviewed By: sbuggay Differential Revision: D95981881 fbshipit-source-id: 76f492f0ceb6b3efea3fce822036ed6cb6067b83
Summary: Pull Request resolved: facebook#56048 Update Android frame screenshot processing to skip screenshot capture when encoding is already in progress — now limited to a single background thread — while always emitting frame timing events. **Motivation** 1. Prevents truncated trace data on slower devices (e.g. missing screenshots for the last 1/3 of the trace), with the tradeoff of some intermediate frame screenshot loss. 2. Reduces total recording overhead by freeing up device threads - prevents excessive encoding work from blocking or slowing down the UI and other app threads. **Algorithm** Uses `encodingInProgress` atomic flag with single encoding thread and `lastFrameBuffer` storage for tail-capture of the last frame before idling (to capture settled animation states): - **Not encoding:** Frame passes directly to encoder → emits with screenshot when done - **Encoding busy:** Frame stored in `lastFrameBuffer` for tail-capture → any replaced frame emits without screenshot - **Encoding done:** Clears flag early, then opportunistically encodes tail frame without blocking new frames - **Failed captures:** Emit without screenshot immediately Result: Every frame emitted exactly once. Encoding adapts to device speed. Settled animation state guaranteed captured. **Remaining work** -⚠️ This still does not yet solve crashes (OkHttp network chunk size overflow) for heavy frame data at a high FPS on fast devices (coming next). Changelog: [Internal] Reviewed By: rubennorte Differential Revision: D95987488 fbshipit-source-id: cda5758e3091edd227d3838638ba157dbcea52d8
) Summary: Pull Request resolved: facebook#56080 Trace event chunks were previously split by a fixed event count (1000). This caused issues with Frame Timing events containing screenshot data, where a single chunk could produce CDP messages of tens or hundreds of MBs — exceeding the OkHttp WebSocket limit (app crash). Address this problem by replacing count-based chunking with size-based chunking (max 10 MiB per chunk) for `emitFrameTimings()` and `emitPerformanceTraceEvents()`. A new `TraceEventSerializer::estimateJsonSize()` utility recursively estimates the serialized byte size of a `folly::dynamic` value to avoid double-serialization overhead. **Notes** - RuntimeSamplingProfile chunks (separate code path) remain count-based (inherently small, no screenshot data). Changelog: [Internal] Reviewed By: rubennorte Differential Revision: D96206962 fbshipit-source-id: 6b6e4db76441f174c46bf34905292585d0e30899
Summary: Pull Request resolved: facebook#56079 Stacked on the current set of improvements, now further increase screenshot quality on Android. Changelog: [Internal] Reviewed By: rubennorte Differential Revision: D96382172 fbshipit-source-id: 1f850d249142a7438eb0064194fac16ce6c9ae89
Summary: Pull Request resolved: facebook#56307 Implement the `Page.captureScreenshot` CDP command in the inspector backend, allowing DevTools to capture an on-demand screenshot of the current app view. This is a minimal implementation supporting only the `format` (jpeg/png/webp) and `quality` (0-100, jpeg only) parameters, returning base64-encoded image data. The feature is gated behind a new `fuseboxCaptureScreenshotEnabled` React Native feature flag, wired through `InspectorFlags` following the same pattern as frame recording. **Motivation** Improve agent verification / user feedback during AI sessions. We've proven that screenshots (in performance traces) are useful for understanding how components render on screen, and exposing this as an on-demand CDP method is relatively cheap today vs the larger task of modelling the DOM (Elements panel). **Changes** - New `fuseboxCaptureScreenshotEnabled` feature flag + `InspectorFlags` wiring (C++, Android JNI, Kotlin) - `HostTargetDelegate::captureScreenshot()` virtual method with async callback - C++ CDP handler in `HostAgent` — parses `format`/`quality`, delegates to platform, sends async CDP response (gated by flag) - iOS (`RCTHost.mm`): Captures key window via `UIGraphicsImageRenderer` + `drawViewHierarchyInRect`, encodes to PNG/JPEG - Android (`ReactHostImpl.kt`): Captures decor view via `Bitmap` + `Canvas` + `View.draw()`, encodes to PNG/JPEG/WebP - 4 C++ tests: success, failure, param forwarding, flag-disabled rejection Changelog: [Internal] Reviewed By: hoxyq Differential Revision: D99099930 fbshipit-source-id: d4d2ef86ba20d2ee230903e152dd21e11f29cbb8
Summary: Pull Request resolved: facebook#56352 Add mutex to protect `PerformanceObserver::buffer_` and `didScheduleFlushBuffer_`, which can be accessed concurrently from a background thread (`handleEntry`) and JS thread (`takeRecords`). Fixes T263429319. Changelog: [Internal] Reviewed By: jorge-cab Differential Revision: D99820359 fbshipit-source-id: 068fa1871b3a0feeb84b950b0c8f5fe7dcf38b7d
Summary: Pull Request resolved: facebook#56135 Ports the dynamic sampling algorithm from Android (D95987488) to iOS. Uses an `encodingInProgress` atomic flag with a single encoding thread and `lastFrameData` buffer to skip screenshot encoding when the encoder is busy, while always emitting frame timing events. This prevents truncated trace data on slower devices and reduces recording overhead. Changelog: [Internal] Reviewed By: rubennorte Differential Revision: D97131485 fbshipit-source-id: 5c30f1052d5b5a61f27f2ab90946ef47b8b6b279
Summary: Pull Request resolved: facebook#56136 Following D97131485, brings iOS screenshot recording to parity with Android. NOTE: Dynamic frame sampling (D97131485) becomes more load bearing after this change, as a 1x scale increases processing overhead significantly. Let's continue dogfooding. Changelog: [Internal] Reviewed By: rubennorte Differential Revision: D97131484 fbshipit-source-id: 4c03842ae22b905a50f989ff68fece7acc289a67
Summary: Pull Request resolved: facebook#56397 The `React-RuntimeApple` pod/target was missing the `REACT_NATIVE_DEBUGGER_ENABLED` preprocessor define in both open source build configurations. Without this, the experimental-and-flagged `fuseboxFrameRecordingEnabled` feature (D95566220) was misbehaving on iOS — code paths in `RCTHost.mm` were unexpectedly compiled out. See facebook#56372. Changelog: [Internal] Reviewed By: rubennorte Differential Revision: D100157250 fbshipit-source-id: 8c11287f34ac6029dd1153a01fed6ba93cc7d398
|
Warning JavaScript API change detected This PR commits an update to
This change was flagged as: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Cherry-pick of 14 commits from
mainbringing Performance debugging features to0.85-stable. These commits landed onmainafter the 0.85 branch point and were previously backported to0.83-stableas a squashed commit in #56372.Changes included
base64Encodeintoreact/utils(Move base64Encode into react/utils #55873)fuseboxFrameRecordingEnabledflag, gate existing code (Introduce fuseboxFrameRecordingEnabled flag, gate existing code #55941)RCTFrameTimingsObserver(Add pixel diffing to RCTFrameTimingsObserver #56043)Page.captureScreenshotCDP support (Add Page.captureScreenshot CDP support (#56307) #56307)PerformanceObserverentry buffer (Fix data race on PerformanceObserver entry buffer #56352)All new features are gated behind
fuseboxFrameRecordingEnabledandfuseboxScreenshotCaptureEnabledfeature flags (both disabled by default).Two commits required regeneration of feature flag files (
yarn featureflags --update) due to the new flags; all other commits applied cleanly.Changelog:
[Internal]
Test Plan
cc @huntie