Skip to content

Commit 6a0b9d1

Browse files
sbuggayfacebook-github-bot
authored andcommitted
Add Analyze Performance option to DevMenu (facebook#53334)
Summary: Pull Request resolved: facebook#53334 Adds background performance tracing options to the DevMenu based on the current background tracing state. Analyzing a trace will automatically open dev tools, navigate to the performance tab, and show the last 20 seconds of recorded performance data. Changelog: [Internal] Reviewed By: javache Differential Revision: D79714164 fbshipit-source-id: 72ad4be4604c5f4e304b49877b2699be36562655
1 parent 84472d9 commit 6a0b9d1

17 files changed

Lines changed: 231 additions & 20 deletions

File tree

packages/react-native/ReactAndroid/api/ReactAndroid.api

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2223,6 +2223,15 @@ public abstract interface class com/facebook/react/devsupport/interfaces/StackFr
22232223
public abstract fun toJSON ()Lorg/json/JSONObject;
22242224
}
22252225

2226+
public final class com/facebook/react/devsupport/interfaces/TracingState : java/lang/Enum {
2227+
public static final field DISABLED Lcom/facebook/react/devsupport/interfaces/TracingState;
2228+
public static final field ENABLEDINBACKGROUNDMODE Lcom/facebook/react/devsupport/interfaces/TracingState;
2229+
public static final field ENABLEDINCDPMODE Lcom/facebook/react/devsupport/interfaces/TracingState;
2230+
public static fun getEntries ()Lkotlin/enums/EnumEntries;
2231+
public static fun valueOf (Ljava/lang/String;)Lcom/facebook/react/devsupport/interfaces/TracingState;
2232+
public static fun values ()[Lcom/facebook/react/devsupport/interfaces/TracingState;
2233+
}
2234+
22262235
public final class com/facebook/react/fabric/ComponentFactory {
22272236
public fun <init> ()V
22282237
}

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/BridgelessDevSupportManager.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import com.facebook.react.devsupport.interfaces.DevLoadingViewManager
1515
import com.facebook.react.devsupport.interfaces.DevSupportManager
1616
import com.facebook.react.devsupport.interfaces.PausedInDebuggerOverlayManager
1717
import com.facebook.react.devsupport.interfaces.RedBoxHandler
18+
import com.facebook.react.devsupport.interfaces.TracingState
1819
import com.facebook.react.packagerconnection.RequestHandler
1920

2021
/**
@@ -80,4 +81,8 @@ internal class BridgelessDevSupportManager(
8081
hideRedboxDialog()
8182
reactInstanceDevHelper.reload("BridgelessDevSupportManager.handleReloadJS()")
8283
}
84+
85+
fun tracingState(): TracingState {
86+
return TracingState.DISABLED
87+
}
8388
}

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerBase.kt

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ import com.facebook.react.devsupport.InspectorFlags.getFuseboxEnabled
5252
import com.facebook.react.devsupport.StackTraceHelper.convertJavaStackTrace
5353
import com.facebook.react.devsupport.StackTraceHelper.convertJsStackTrace
5454
import com.facebook.react.devsupport.interfaces.BundleLoadCallback
55+
import com.facebook.react.devsupport.interfaces.DebuggerFrontendPanelName
5556
import com.facebook.react.devsupport.interfaces.DevBundleDownloadListener
5657
import com.facebook.react.devsupport.interfaces.DevLoadingViewManager
5758
import com.facebook.react.devsupport.interfaces.DevOptionHandler
@@ -64,6 +65,8 @@ import com.facebook.react.devsupport.interfaces.PackagerStatusCallback
6465
import com.facebook.react.devsupport.interfaces.PausedInDebuggerOverlayManager
6566
import com.facebook.react.devsupport.interfaces.RedBoxHandler
6667
import com.facebook.react.devsupport.interfaces.StackFrame
68+
import com.facebook.react.devsupport.interfaces.TracingState
69+
import com.facebook.react.devsupport.interfaces.TracingStateProvider
6770
import com.facebook.react.devsupport.perfmonitor.PerfMonitorDevHelper
6871
import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags
6972
import com.facebook.react.internal.featureflags.ReactNativeNewArchitectureFeatureFlags
@@ -180,6 +183,7 @@ public abstract class DevSupportManagerBase(
180183
}
181184

182185
private var perfMonitorOverlayManager: PerfMonitorOverlayViewManager? = null
186+
private var tracingStateProvider: TracingStateProvider? = null
183187

184188
init {
185189
// We store JS bundle loaded from dev server in a single destination in app's data dir.
@@ -358,6 +362,43 @@ public abstract class DevSupportManagerBase(
358362
options[debuggerItemString] = DevOptionHandler { this.openDebugger() }
359363
}
360364

365+
if (ReactNativeFeatureFlags.perfMonitorV2Enabled()) {
366+
val isConnected = isPackagerConnected
367+
val tracingState = tracingStateProvider?.getTracingState() ?: TracingState.DISABLED
368+
369+
val analyzePerformanceItemString =
370+
when (tracingState) {
371+
TracingState.ENABLEDINBACKGROUNDMODE ->
372+
applicationContext.getString(R.string.catalyst_performance_background)
373+
TracingState.ENABLEDINCDPMODE ->
374+
applicationContext.getString(R.string.catalyst_performance_cdp)
375+
TracingState.DISABLED ->
376+
applicationContext.getString(R.string.catalyst_performance_disabled)
377+
}
378+
379+
if (!isConnected || tracingState == TracingState.ENABLEDINCDPMODE) {
380+
disabledItemKeys.add(analyzePerformanceItemString)
381+
}
382+
383+
options[analyzePerformanceItemString] =
384+
when (tracingState) {
385+
TracingState.ENABLEDINBACKGROUNDMODE ->
386+
DevOptionHandler {
387+
UiThreadUtil.runOnUiThread {
388+
if (reactInstanceDevHelper is PerfMonitorDevHelper)
389+
reactInstanceDevHelper.inspectorTarget?.pauseAndAnalyzeBackgroundTrace()
390+
}
391+
openDebugger(DebuggerFrontendPanelName.PERFORMANCE.toString())
392+
}
393+
TracingState.DISABLED ->
394+
DevOptionHandler {
395+
if (reactInstanceDevHelper is PerfMonitorDevHelper)
396+
reactInstanceDevHelper.inspectorTarget?.resumeBackgroundTrace()
397+
}
398+
TracingState.ENABLEDINCDPMODE -> DevOptionHandler {}
399+
}
400+
}
401+
361402
options[applicationContext.getString(R.string.catalyst_change_bundle_location)] =
362403
DevOptionHandler {
363404
val context = reactInstanceDevHelper.currentActivity
@@ -942,6 +983,14 @@ public abstract class DevSupportManagerBase(
942983
devSettings.packagerConnectionSettings.setAdditionalOptionForPackager(name, value)
943984
}
944985

986+
/**
987+
* Sets the background tracing state provider for bridgeless architecture. This is called
988+
* internally by the ReactHost implementation.
989+
*/
990+
internal fun setTracingStateProvider(provider: TracingStateProvider?) {
991+
tracingStateProvider = provider
992+
}
993+
945994
public companion object {
946995
private const val JAVA_ERROR_COOKIE = -1
947996
private const val JSEXCEPTION_ERROR_COOKIE = -1

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/PerfMonitorOverlayViewManager.kt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import androidx.core.view.WindowInsetsCompat
2626
import com.facebook.react.R
2727
import com.facebook.react.bridge.UiThreadUtil
2828
import com.facebook.react.devsupport.interfaces.PerfMonitorOverlayManager
29+
import com.facebook.react.devsupport.interfaces.TracingState
2930
import com.facebook.react.devsupport.perfmonitor.PerfMonitorInspectorTargetBinding
3031
import com.facebook.react.devsupport.perfmonitor.PerfMonitorUpdateListener
3132
import com.facebook.react.uimanager.DisplayMetricsHolder
@@ -68,6 +69,11 @@ internal class PerfMonitorOverlayViewManager(
6869
}
6970
}
7071

72+
override fun onRecordingStateChanged(state: TracingState) {
73+
// recordingState = state
74+
// view?.updateRecordingState(state)
75+
}
76+
7177
override fun onNewFocusedEvent(data: PerfMonitorUpdateListener.LongTaskEventData) {
7278
UiThreadUtil.runOnUiThread {
7379
ensureInitialized()
@@ -148,6 +154,8 @@ internal class PerfMonitorOverlayViewManager(
148154
this.interactionDialog = dialog
149155
}
150156

157+
fun updateRecordingState(state: TracingState) {}
158+
151159
private fun createButton(context: Context) {
152160
val buttonInner = createInnerLayout(context)
153161
buttonInner.addView(
@@ -177,7 +185,7 @@ internal class PerfMonitorOverlayViewManager(
177185
dpToPx(8f).toInt(),
178186
)
179187
addView(buttonInner)
180-
setOnClickListener { inspectorTarget?.pauseAndAnalyzeTrace() }
188+
setOnClickListener { inspectorTarget?.pauseAndAnalyzeBackgroundTrace() }
181189
}
182190
val dialog =
183191
createAnchoredDialog(context, dpToPx(0f), dpToPx(0f)).apply { setContentView(buttonView) }
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
package com.facebook.react.devsupport.interfaces
9+
10+
import com.facebook.proguard.annotations.DoNotStripAny
11+
12+
// Keep in sync with `TracingState.h`
13+
// JNI wrapper for `jsinspector_modern::Tracing::TracingState`.
14+
@DoNotStripAny
15+
public enum class TracingState {
16+
DISABLED, // There is no active trace
17+
ENABLEDINBACKGROUNDMODE, // Trace is currently running in background mode
18+
ENABLEDINCDPMODE, // Trace is currently running in CDP mode
19+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
package com.facebook.react.devsupport.interfaces
9+
10+
internal interface TracingStateProvider {
11+
fun getTracingState(): TracingState
12+
}

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/perfmonitor/PerfMonitorInspectorTargetBinding.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,9 @@ package com.facebook.react.devsupport.perfmonitor
1212
* exposing actions for the V2 Perf Monitor.
1313
*/
1414
internal interface PerfMonitorInspectorTargetBinding {
15-
public fun pauseAndAnalyzeTrace()
15+
/** Attempt to pause the current background performance trace, and open in DevTools. */
16+
public fun pauseAndAnalyzeBackgroundTrace()
17+
18+
/** Attempt to start a new background performance trace. */
19+
public fun resumeBackgroundTrace()
1620
}

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/perfmonitor/PerfMonitorUpdateListener.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*/
7-
87
package com.facebook.react.devsupport.perfmonitor
98

9+
import com.facebook.react.devsupport.interfaces.TracingState
10+
1011
/** [Experimental] An interface for subscribing to updates for the V2 Perf Monitor. */
1112
internal interface PerfMonitorUpdateListener {
1213
data class LongTaskEventData(
@@ -17,4 +18,7 @@ internal interface PerfMonitorUpdateListener {
1718

1819
/** Called when a new active performance event should be displayed. */
1920
fun onNewFocusedEvent(data: LongTaskEventData)
21+
22+
/** Called when the recording state of the background performance trace has changed. */
23+
fun onRecordingStateChanged(state: TracingState)
2024
}

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactHostImpl.kt

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -95,21 +95,30 @@ public class ReactHostImpl(
9595
private val useDevSupport: Boolean,
9696
devSupportManagerFactory: DevSupportManagerFactory? = null,
9797
) : ReactHost {
98+
private val reactHostImplDevHelper = ReactHostImplDevHelper(this)
99+
98100
public override val devSupportManager: DevSupportManager =
99-
(devSupportManagerFactory ?: DefaultDevSupportManagerFactory()).create(
100-
applicationContext = context.applicationContext,
101-
reactInstanceManagerHelper = ReactHostImplDevHelper(this),
102-
packagerPathForJSBundleName = reactHostDelegate.jsMainModulePath,
103-
enableOnCreate = true,
104-
redBoxHandler = null,
105-
devBundleDownloadListener = null,
106-
minNumShakes = 2,
107-
customPackagerCommandHandlers = null,
108-
surfaceDelegateFactory = null,
109-
devLoadingViewManager = null,
110-
pausedInDebuggerOverlayManager = null,
111-
useDevSupport = useDevSupport,
112-
)
101+
(devSupportManagerFactory ?: DefaultDevSupportManagerFactory())
102+
.create(
103+
applicationContext = context.applicationContext,
104+
reactInstanceManagerHelper = reactHostImplDevHelper,
105+
packagerPathForJSBundleName = reactHostDelegate.jsMainModulePath,
106+
enableOnCreate = true,
107+
redBoxHandler = null,
108+
devBundleDownloadListener = null,
109+
minNumShakes = 2,
110+
customPackagerCommandHandlers = null,
111+
surfaceDelegateFactory = null,
112+
devLoadingViewManager = null,
113+
pausedInDebuggerOverlayManager = null,
114+
useDevSupport = useDevSupport,
115+
)
116+
.also { devSupportManager ->
117+
// Wire up the tracing state provider
118+
if (devSupportManager is DevSupportManagerBase) {
119+
devSupportManager.setTracingStateProvider(reactHostImplDevHelper)
120+
}
121+
}
113122
public override val memoryPressureRouter: MemoryPressureRouter = MemoryPressureRouter(context)
114123

115124
private val attachedSurfaces: MutableSet<ReactSurfaceImpl> = HashSet()

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactHostImplDevHelper.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import com.facebook.react.bridge.ReactContext
1616
import com.facebook.react.common.annotations.FrameworkAPI
1717
import com.facebook.react.common.annotations.UnstableReactNativeAPI
1818
import com.facebook.react.devsupport.ReactInstanceDevHelper
19+
import com.facebook.react.devsupport.interfaces.TracingState
20+
import com.facebook.react.devsupport.interfaces.TracingStateProvider
1921
import com.facebook.react.devsupport.perfmonitor.PerfMonitorDevHelper
2022
import com.facebook.react.devsupport.perfmonitor.PerfMonitorInspectorTarget
2123
import com.facebook.react.interfaces.TaskInterface
@@ -30,7 +32,7 @@ import com.facebook.react.modules.core.DeviceEventManagerModule
3032
@UnstableReactNativeAPI
3133
@OptIn(FrameworkAPI::class)
3234
internal class ReactHostImplDevHelper(private val delegate: ReactHostImpl) :
33-
ReactInstanceDevHelper, PerfMonitorDevHelper {
35+
ReactInstanceDevHelper, PerfMonitorDevHelper, TracingStateProvider {
3436

3537
override val currentActivity: Activity?
3638
get() = delegate.lastUsedActivity
@@ -77,4 +79,8 @@ internal class ReactHostImplDevHelper(private val delegate: ReactHostImpl) :
7779

7880
override fun loadBundle(bundleLoader: JSBundleLoader): TaskInterface<Boolean> =
7981
delegate.loadBundle(bundleLoader)
82+
83+
override fun getTracingState(): TracingState {
84+
return delegate.reactHostInspectorTarget?.tracingState() ?: TracingState.DISABLED
85+
}
8086
}

0 commit comments

Comments
 (0)