From feec8d014877b2177f1c7dded7eb9664f53ee471 Mon Sep 17 00:00:00 2001 From: Nicola Corti Date: Fri, 13 Jun 2025 14:08:01 -0700 Subject: [PATCH] Hide JS FPS on performance overlay as not accurate (#52000) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/52000 Fixes https://github.com/facebook/react-native/issues/50338 The current JS FPS value is incorrect because the frame skipping logic hasn't been reimplemented in Fabric. As we're looking into moving this into the performance panel, I've discussed with huntie and agreed we'll just remove the value for now to don't show inaccurate informations. Changelog: [Android] [Changed] - Hide JS FPS on performance overlay as not accurate Reviewed By: huntie Differential Revision: D76590909 fbshipit-source-id: 90b0d9c84f9aefa9197243ebb57f4e86107d6c01 --- .../com/facebook/react/devsupport/FpsView.kt | 23 +++++++++++++------ .../modules/debug/FpsDebugFrameCallback.kt | 12 ++++++++++ 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/FpsView.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/FpsView.kt index 4c46a1f6b24..88ef08dbc1d 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/FpsView.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/FpsView.kt @@ -33,7 +33,7 @@ internal class FpsView(reactContext: ReactContext?) : FrameLayout(reactContext!! textView = findViewById(R.id.fps_text) as TextView frameCallback = FpsDebugFrameCallback(reactContext!!) fpsMonitorRunnable = FPSMonitorRunnable() - setCurrentFPS(0.0, 0.0, 0, 0) + setCurrentFPS(0.0, 0.0, 0, 0, frameCallback.isRunningOnFabric) } override fun onAttachedToWindow() { @@ -53,16 +53,21 @@ internal class FpsView(reactContext: ReactContext?) : FrameLayout(reactContext!! currentFPS: Double, currentJSFPS: Double, droppedUIFrames: Int, - total4PlusFrameStutters: Int + total4PlusFrameStutters: Int, + runningOnFabric: Boolean ) { - val fpsString = + var fpsString = String.format( Locale.US, - "UI: %.1f fps\n%d dropped so far\n%d stutters (4+) so far\nJS: %.1f fps", + "UI: %.1f fps\n%d dropped so far\n%d stutters (4+) so far", currentFPS, droppedUIFrames, - total4PlusFrameStutters, - currentJSFPS) + total4PlusFrameStutters) + if (!runningOnFabric) { + // The JS FPS is only relevant for the legacy architecture, as Fabric we don't use + // BridgeIdleDebugListener to track JS frame drops. + fpsString += String.format(Locale.US, "\nJS: %.1f fps", currentJSFPS) + } textView.text = fpsString FLog.d(ReactConstants.TAG, fpsString) } @@ -80,7 +85,11 @@ internal class FpsView(reactContext: ReactContext?) : FrameLayout(reactContext!! totalFramesDropped += frameCallback.expectedNumFrames - frameCallback.numFrames total4PlusFrameStutters += frameCallback.get4PlusFrameStutters() setCurrentFPS( - frameCallback.fps, frameCallback.jsFPS, totalFramesDropped, total4PlusFrameStutters) + frameCallback.fps, + frameCallback.jsFPS, + totalFramesDropped, + total4PlusFrameStutters, + frameCallback.isRunningOnFabric) frameCallback.reset() postDelayed(this, UPDATE_INTERVAL_MS.toLong()) } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/debug/FpsDebugFrameCallback.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/debug/FpsDebugFrameCallback.kt index 49ab4609d51..15358927df2 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/debug/FpsDebugFrameCallback.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/debug/FpsDebugFrameCallback.kt @@ -65,6 +65,11 @@ internal class FpsDebugFrameCallback(private val reactContext: ReactContext) : val uiManagerModule = reactContext.getNativeModule(UIManagerModule::class.java) if (!reactContext.isBridgeless) { reactContext.catalystInstance.addBridgeIdleDebugListener(didJSUpdateUiDuringFrameDetector) + isRunningOnFabric = false + } else { + // T172641976 Consider either implementing a mechanism similar to addBridgeIdleDebugListener + // for Fabric or point users to use RNDT. + isRunningOnFabric = true } uiManagerModule?.setViewHierarchyUpdateDebugListener(didJSUpdateUiDuringFrameDetector) } @@ -97,6 +102,10 @@ internal class FpsDebugFrameCallback(private val reactContext: ReactContext) : 0.0 } else numFrames.toDouble() * 1e9 / (lastFrameTime - firstFrameTime) + /** + * Please note that this value is not relevant if running on Fabric. That's because we don't + * implement addBridgeIdleDebugListener on Fabric. + */ val jsFPS: Double get() = if (lastFrameTime == firstFrameTime) { @@ -115,6 +124,9 @@ internal class FpsDebugFrameCallback(private val reactContext: ReactContext) : return (targetFps * totalTimeMS / 1000 + 1).toInt() } + var isRunningOnFabric = true + private set + fun get4PlusFrameStutters(): Int = fourPlusFrameStutters private val totalTimeMS: Int