Skip to content

Commit 6e011c9

Browse files
huntiefacebook-github-bot
authored andcommitted
Strip back V2 Perf Monitor to status only (#53742)
Summary: Pull Request resolved: #53742 Simplify scope for the internal V2 Perf Monitor prototype, and clean up the current perf metrics approach. Changelog: [Internal] Reviewed By: hoxyq Differential Revision: D82208400 fbshipit-source-id: a03eb5f493064fc4b554d56a36a48df889f276b2
1 parent 0ee665c commit 6e011c9

17 files changed

Lines changed: 49 additions & 459 deletions

File tree

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,6 @@ public abstract class DevSupportManagerBase(
229229
}
230230
context
231231
},
232-
{ openDebugger(DebuggerFrontendPanelName.PERFORMANCE.toString()) },
233232
)
234233
}
235234
}

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

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,10 @@ import javax.inject.Provider
1515
internal class PerfMonitorOverlayManager(
1616
private val devHelper: PerfMonitorDevHelper,
1717
private val contextProvider: Provider<Context?>,
18-
private val onRequestOpenDevTools: () -> Unit,
1918
) : PerfMonitorUpdateListener {
2019
private var enabled: Boolean = false
2120
private var initialized: Boolean = false
2221
private var view: PerfMonitorOverlayView? = null
23-
private var tracingState: TracingState = TracingState.ENABLEDINCDPMODE
2422

2523
private fun init() {
2624
if (initialized || !enabled) {
@@ -29,7 +27,7 @@ internal class PerfMonitorOverlayManager(
2927

3028
UiThreadUtil.runOnUiThread {
3129
val context = contextProvider.get() ?: return@runOnUiThread
32-
view = PerfMonitorOverlayView(context, ::handleRecordingButtonPress)
30+
view = PerfMonitorOverlayView(context)
3331

3432
// Start background tracing
3533
devHelper.inspectorTarget?.resumeBackgroundTrace()
@@ -43,44 +41,24 @@ internal class PerfMonitorOverlayManager(
4341
fun enable() {
4442
enabled = true
4543
init()
46-
UiThreadUtil.runOnUiThread { view?.show() }
4744
}
4845

4946
/** Disable the Perf Monitor overlay. Will remain hidden when updates are received. */
5047
fun disable() {
5148
UiThreadUtil.runOnUiThread { view?.hide() }
49+
view = null
5250
enabled = false
5351
}
5452

5553
/** Reset the Perf Monitor overlay, e.g. after a reload. */
5654
fun reset() {
57-
UiThreadUtil.runOnUiThread { view?.resetState() }
58-
5955
// Update with current recording state
6056
onRecordingStateChanged(
6157
devHelper.inspectorTarget?.getTracingState() ?: TracingState.ENABLEDINCDPMODE
6258
)
6359
}
6460

65-
override fun onNewFocusedEvent(data: PerfMonitorUpdateListener.LongTaskEventData) {
66-
view?.updateFocusedEvent(data)
67-
}
68-
6961
override fun onRecordingStateChanged(state: TracingState) {
70-
tracingState = state
7162
view?.updateRecordingState(state)
7263
}
73-
74-
private fun handleRecordingButtonPress() {
75-
when (tracingState) {
76-
TracingState.ENABLEDINBACKGROUNDMODE -> {
77-
devHelper.inspectorTarget?.pauseAndAnalyzeBackgroundTrace()
78-
onRequestOpenDevTools()
79-
}
80-
TracingState.DISABLED -> {
81-
devHelper.inspectorTarget?.resumeBackgroundTrace()
82-
}
83-
TracingState.ENABLEDINCDPMODE -> Unit
84-
}
85-
}
8664
}

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

Lines changed: 46 additions & 169 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@ import android.graphics.Color
1313
import android.graphics.Typeface
1414
import android.graphics.drawable.ColorDrawable
1515
import android.graphics.drawable.GradientDrawable
16-
import android.os.Handler
17-
import android.os.Looper
1816
import android.view.Gravity
1917
import android.view.Window
2018
import android.view.WindowManager
@@ -26,186 +24,88 @@ import com.facebook.react.R
2624
import com.facebook.react.devsupport.interfaces.TracingState
2725
import com.facebook.react.uimanager.DisplayMetricsHolder
2826
import com.facebook.react.uimanager.PixelUtil
29-
import java.util.Locale
3027

3128
internal class PerfMonitorOverlayView(
3229
private val context: Context,
33-
private val onButtonPress: () -> Unit,
3430
) {
35-
private var hidden: Boolean = true
36-
private var hasEventData: Boolean = false
37-
private val metricsDialog: Dialog
38-
private val toolbarDialog: Dialog
39-
private val tooltipDialog: Dialog
40-
private lateinit var buttonLabel: TextView
41-
private lateinit var recordingStateLabel: TextView
42-
private lateinit var durationLabel: TextView
31+
private val dialog: Dialog
32+
private lateinit var statusLabel: TextView
4333
private lateinit var tooltipLabel: TextView
44-
private var ttl: Int = 0
45-
private var hideAfterTimeoutHandler: Handler? = null
34+
private lateinit var statusIndicator: TextView
4635

4736
init {
4837
DisplayMetricsHolder.initDisplayMetricsIfNotInitialized(context)
49-
tooltipDialog = createTooltipDialog()
50-
metricsDialog = createMetricsDialog()
51-
toolbarDialog = createToolbarDialog()
38+
dialog = createToolbarDialog()
5239
}
5340

5441
fun show() {
55-
toolbarDialog.show()
56-
tooltipDialog.show()
57-
if (hasEventData) {
58-
toolbarDialog.window?.decorView?.post { updateMetricsDialogPosition() }
59-
metricsDialog.show()
60-
}
61-
hidden = false
42+
dialog.show()
6243
}
6344

6445
fun hide() {
65-
metricsDialog.hide()
66-
toolbarDialog.hide()
67-
tooltipDialog.hide()
68-
hidden = true
69-
}
70-
71-
fun resetState() {
72-
hasEventData = false
73-
metricsDialog.hide()
74-
}
75-
76-
fun updateFocusedEvent(data: PerfMonitorUpdateListener.LongTaskEventData) {
77-
durationLabel.text = String.format(Locale.US, "%d ms", data.durationMs)
78-
durationLabel.setTextColor(getDurationHighlightColor(data.responsivenessScore))
79-
hasEventData = true
80-
ttl = data.ttl
81-
82-
hideAfterTimeoutHandler?.removeCallbacksAndMessages(null)
83-
84-
if (!hidden) {
85-
metricsDialog.show()
86-
87-
// Schedule hiding metrics overlay after ttl milliseconds
88-
if (ttl > 0) {
89-
if (hideAfterTimeoutHandler == null) {
90-
hideAfterTimeoutHandler = Handler(Looper.getMainLooper())
91-
}
92-
hideAfterTimeoutHandler?.postDelayed({ metricsDialog.hide() }, ttl.toLong())
93-
}
94-
}
46+
dialog.hide()
9547
}
9648

9749
fun updateRecordingState(state: TracingState) {
98-
recordingStateLabel.text =
99-
when (state) {
100-
TracingState.ENABLEDINBACKGROUNDMODE -> "Profiling: ON"
101-
TracingState.DISABLED -> "Profiling: OFF"
102-
TracingState.ENABLEDINCDPMODE -> "Profiling: DISABLED"
103-
}
104-
buttonLabel.text =
105-
when (state) {
106-
TracingState.ENABLEDINBACKGROUNDMODE -> "Open ↗️"
107-
TracingState.DISABLED -> "Start"
108-
TracingState.ENABLEDINCDPMODE -> ""
109-
}
110-
tooltipLabel.text =
111-
when (state) {
112-
TracingState.ENABLEDINBACKGROUNDMODE -> "Dev Menu > Finish performance trace"
113-
TracingState.DISABLED -> "Dev Menu > Start performance trace"
114-
TracingState.ENABLEDINCDPMODE -> ""
115-
}
11650
if (state == TracingState.ENABLEDINCDPMODE) {
117-
tooltipDialog.hide()
118-
} else {
119-
tooltipDialog.show()
51+
dialog.hide()
52+
return
12053
}
12154

122-
toolbarDialog.window?.decorView?.post { updateMetricsDialogPosition() }
55+
if (state == TracingState.ENABLEDINBACKGROUNDMODE) {
56+
(statusIndicator.background as GradientDrawable).setColor(Color.RED)
57+
statusLabel.text = "Background Profiling Active"
58+
tooltipLabel.text = "Press ☰ to open"
59+
} else {
60+
(statusIndicator.background as GradientDrawable).setColor(Color.GRAY)
61+
statusLabel.text = "Background Profiling Stopped"
62+
tooltipLabel.text = "Press ☰ to restart"
63+
}
64+
dialog.show()
12365
}
12466

125-
private fun createMetricsDialog(): Dialog {
126-
val containerLayout = createInnerLayout()
127-
val longTaskLabel =
128-
TextView(context).apply {
129-
textSize = TEXT_SIZE_PRIMARY
130-
text = "Long Task"
131-
setTextColor(Color.WHITE)
132-
typeface = TYPEFACE_BOLD
133-
}
134-
durationLabel =
67+
private fun createToolbarDialog(): Dialog {
68+
statusIndicator =
13569
TextView(context).apply {
136-
textSize = TEXT_SIZE_PRIMARY
137-
setTextColor(COLOR_TEXT_GREEN)
138-
typeface = TYPEFACE_BOLD
70+
width = dpToPx(12f).toInt()
71+
height = dpToPx(12f).toInt()
72+
background =
73+
GradientDrawable().apply {
74+
shape = GradientDrawable.OVAL
75+
setColor(Color.RED)
76+
}
13977
}
140-
containerLayout.addView(longTaskLabel)
141-
containerLayout.addView(durationLabel)
14278

143-
val dialog =
144-
createAnchoredDialog(getMetricsDialogOffsetX(), dpToPx(16f)).apply {
145-
setContentView(containerLayout)
79+
val textContainer =
80+
LinearLayout(context).apply {
81+
orientation = LinearLayout.VERTICAL
82+
layoutParams =
83+
LinearLayout.LayoutParams(
84+
LinearLayout.LayoutParams.WRAP_CONTENT,
85+
LinearLayout.LayoutParams.WRAP_CONTENT,
86+
)
14687
}
147-
dialog.window?.apply {
148-
attributes =
149-
attributes?.apply {
150-
flags =
151-
flags or
152-
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE or
153-
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
154-
}
155-
}
156-
157-
return dialog
158-
}
159-
160-
private fun createToolbarDialog(): Dialog {
161-
val buttonInner = createInnerLayout()
162-
recordingStateLabel =
88+
statusLabel =
16389
TextView(context).apply {
16490
textSize = TEXT_SIZE_PRIMARY
16591
setTextColor(Color.WHITE)
16692
typeface = TYPEFACE_BOLD
16793
}
168-
buttonInner.addView(recordingStateLabel)
169-
buttonLabel =
170-
TextView(context).apply {
171-
textSize = TEXT_SIZE_PRIMARY
172-
setTextColor(COLOR_TEXT_BLUE)
173-
typeface = TYPEFACE_BOLD
174-
}
175-
buttonInner.addView(buttonLabel)
176-
val buttonView =
177-
LinearLayout(context).apply {
178-
orientation = LinearLayout.VERTICAL
179-
setPadding(
180-
dpToPx(8f).toInt(),
181-
dpToPx(16f).toInt(),
182-
dpToPx(16f).toInt(),
183-
dpToPx(8f).toInt(),
184-
)
185-
addView(buttonInner)
186-
setOnClickListener { onButtonPress() }
187-
}
188-
189-
val dialog = createAnchoredDialog(dpToPx(0f), dpToPx(0f)).apply { setContentView(buttonView) }
190-
dialog.window?.apply {
191-
attributes =
192-
attributes?.apply { flags = flags or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE }
193-
}
194-
195-
return dialog
196-
}
197-
198-
private fun createTooltipDialog(): Dialog {
199-
val containerLayout = createInnerLayout()
20094
tooltipLabel =
20195
TextView(context).apply {
20296
textSize = TEXT_SIZE_ACCESSORY
20397
setTextColor(Color.WHITE)
98+
typeface = TYPEFACE_BOLD
20499
}
205-
containerLayout.addView(tooltipLabel)
100+
textContainer.addView(statusLabel)
101+
textContainer.addView(tooltipLabel)
102+
103+
val containerLayout = createInnerLayout()
104+
containerLayout.addView(statusIndicator)
105+
containerLayout.addView(textContainer)
206106

207107
val dialog =
208-
createAnchoredDialog(dpToPx(16f), dpToPx(52f)).apply { setContentView(containerLayout) }
108+
createAnchoredDialog(dpToPx(12f), dpToPx(12f)).apply { setContentView(containerLayout) }
209109
dialog.window?.apply {
210110
attributes =
211111
attributes?.apply {
@@ -278,35 +178,12 @@ internal class PerfMonitorOverlayView(
278178
}
279179
}
280180

281-
private fun getMetricsDialogOffsetX(): Float {
282-
val toolbarWidth = toolbarDialog?.window?.decorView?.width ?: 0
283-
return toolbarWidth.toFloat()
284-
}
285-
286-
private fun updateMetricsDialogPosition() {
287-
metricsDialog?.window?.apply {
288-
attributes = attributes?.apply { x = getMetricsDialogOffsetX().toInt() }
289-
}
290-
}
291-
292-
private fun getDurationHighlightColor(responsivenessScore: Int): Int {
293-
return when (responsivenessScore) {
294-
2 -> COLOR_TEXT_RED
295-
1 -> COLOR_TEXT_YELLOW
296-
else -> COLOR_TEXT_GREEN
297-
}
298-
}
299-
300181
private fun dpToPx(dp: Float): Float = PixelUtil.toPixelFromDIP(dp)
301182

302183
companion object {
303-
private val COLOR_TEXT_GREEN = Color.parseColor("#4AEB2F")
304-
private val COLOR_TEXT_YELLOW = Color.parseColor("#FFAA00")
305-
private val COLOR_TEXT_RED = Color.parseColor("#FF0000")
306-
private val COLOR_TEXT_BLUE = Color.parseColor("#00B0FF")
307184
private val COLOR_OVERLAY_BORDER = Color.parseColor("#6C6C6C")
308-
private val TEXT_SIZE_PRIMARY = 13f
309-
private val TEXT_SIZE_ACCESSORY = 9f
185+
private val TEXT_SIZE_PRIMARY = 12f
186+
private val TEXT_SIZE_ACCESSORY = 10f
310187
private val TYPEFACE_BOLD = Typeface.create("sans-serif", Typeface.BOLD)
311188
}
312189
}

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

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,6 @@ import com.facebook.react.devsupport.interfaces.TracingState
1010

1111
/** [Experimental] An interface for subscribing to updates for the V2 Perf Monitor. */
1212
internal interface PerfMonitorUpdateListener {
13-
data class LongTaskEventData(
14-
val durationMs: Int,
15-
val responsivenessScore: Int,
16-
val ttl: Int,
17-
)
18-
19-
/** Called when a new active performance event should be displayed. */
20-
fun onNewFocusedEvent(data: LongTaskEventData)
21-
2213
/** Called when the recording state of the background performance trace has changed. */
2314
fun onRecordingStateChanged(state: TracingState)
2415
}

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

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -65,18 +65,6 @@ internal class ReactHostInspectorTarget(reactHostImpl: ReactHostImpl) :
6565
}
6666
}
6767

68-
fun handleNativePerfMonitorMetricUpdate(
69-
longTaskDurationMs: Int,
70-
responsivenessScore: Int,
71-
ttl: Int,
72-
) {
73-
perfMonitorListeners.forEach { listener ->
74-
listener.onNewFocusedEvent(
75-
PerfMonitorUpdateListener.LongTaskEventData(longTaskDurationMs, responsivenessScore, ttl)
76-
)
77-
}
78-
}
79-
8068
override fun close() {
8169
mHybridData.resetNative()
8270
}

0 commit comments

Comments
 (0)