Skip to content

Commit df748ba

Browse files
huntiefacebook-github-bot
authored andcommitted
Implement Perf Monitor event scoring and display timeout (#53169)
Summary: Pull Request resolved: #53169 Improves the experimental Perf Monitor UI sufficient for the initial MVP. - Sets minimum duration threshold to display an event to 10ms. - Impelements [responsiveness scoring](https://web.dev/articles/inp#good-score) linked to UI colour and display timeout. Changelog: [Internal] Reviewed By: rubennorte Differential Revision: D79359131 fbshipit-source-id: f08d2b595e885342d841c3a02b9e02456502c926
1 parent defefb1 commit df748ba

12 files changed

Lines changed: 226 additions & 29 deletions

File tree

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2031,7 +2031,7 @@ public abstract class com/facebook/react/devsupport/DevSupportManagerBase : com/
20312031
public fun startInspector ()V
20322032
public fun stopInspector ()V
20332033
public fun toggleElementInspector ()V
2034-
public fun unstable_updatePerfMonitor (Ljava/lang/String;I)V
2034+
public fun unstable_updatePerfMonitor (Ljava/lang/String;III)V
20352035
}
20362036

20372037
public abstract interface class com/facebook/react/devsupport/DevSupportManagerBase$CallbackWithBundleLoader {

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -927,10 +927,14 @@ public abstract class DevSupportManagerBase(
927927
}
928928

929929
override fun unstable_updatePerfMonitor(
930-
interactionName: String,
930+
eventName: String,
931931
durationMs: Int,
932+
responsivenessScore: Int,
933+
ttl: Int,
932934
) {
933-
perfMonitorOverlayManager?.update(interactionName, durationMs)
935+
perfMonitorOverlayManager?.update(
936+
PerfMonitorOverlayManager.PerfMonitorUpdateData(
937+
eventName, durationMs, responsivenessScore, ttl))
934938
}
935939

936940
override fun setAdditionalOptionForPackager(name: String, value: String) {

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

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ 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
1618
import android.view.Gravity
1719
import android.view.Window
1820
import android.view.WindowManager
@@ -39,6 +41,8 @@ internal class PerfMonitorOverlayViewManager(
3941
private var buttonDialog: Dialog? = null
4042
private var interactionNameLabel: TextView? = null
4143
private var durationLabel: TextView? = null
44+
private var ttl: Int = 0
45+
private var hideAfterTimeoutHandler: Handler? = null
4246

4347
override fun enable() {
4448
UiThreadUtil.runOnUiThread {
@@ -63,14 +67,27 @@ internal class PerfMonitorOverlayViewManager(
6367
}
6468
}
6569

66-
override fun update(interactionName: String, durationMs: Int) {
70+
override fun update(data: PerfMonitorOverlayManager.PerfMonitorUpdateData) {
6771
UiThreadUtil.runOnUiThread {
6872
ensureInitialized()
69-
interactionNameLabel?.text = interactionName
70-
durationLabel?.text = String.format(Locale.US, "%d ms", durationMs)
73+
interactionNameLabel?.text = data.eventName
74+
durationLabel?.text = String.format(Locale.US, "%d ms", data.durationMs)
75+
durationLabel?.setTextColor(getDurationHighlightColor(data.responsivenessScore))
7176
hasInteractionData = true
77+
this.ttl = data.ttl
78+
79+
hideAfterTimeoutHandler?.removeCallbacksAndMessages(null)
80+
7281
if (enabled) {
7382
showOverlay()
83+
84+
// Schedule hiding overlay after ttl milliseconds
85+
if (ttl > 0) {
86+
if (hideAfterTimeoutHandler == null) {
87+
hideAfterTimeoutHandler = Handler(Looper.getMainLooper())
88+
}
89+
hideAfterTimeoutHandler?.postDelayed({ hideOverlay() }, ttl.toLong())
90+
}
7491
}
7592
}
7693
}
@@ -228,10 +245,20 @@ internal class PerfMonitorOverlayViewManager(
228245
}
229246
}
230247

248+
private fun getDurationHighlightColor(responsivenessScore: Int): Int {
249+
return when (responsivenessScore) {
250+
3 -> COLOR_TEXT_RED
251+
2 -> COLOR_TEXT_YELLOW
252+
else -> COLOR_TEXT_GREEN
253+
}
254+
}
255+
231256
private fun dpToPx(dp: Float): Float = PixelUtil.toPixelFromDIP(dp)
232257

233258
companion object {
234259
private val COLOR_TEXT_GREEN = Color.parseColor("#4AEB2F")
260+
private val COLOR_TEXT_YELLOW = Color.parseColor("#FFAA00")
261+
private val COLOR_TEXT_RED = Color.parseColor("#FF0000")
235262
private val COLOR_OVERLAY_BORDER = Color.parseColor("#6C6C6C")
236263
private val TEXT_SIZE_PRIMARY = 13f
237264
private val TEXT_SIZE_ACCESSORY = 9f

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

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@ package com.facebook.react.devsupport.interfaces
99

1010
/** [Experimental] Interface to manage the V2 Perf Monitor overlay. */
1111
internal interface PerfMonitorOverlayManager {
12+
data class PerfMonitorUpdateData(
13+
val eventName: String,
14+
val durationMs: Int,
15+
val responsivenessScore: Int,
16+
val ttl: Int
17+
)
18+
1219
/** Enable the Perf Monitor overlay. Will be shown when updates are received. */
1320
public fun enable()
1421

@@ -19,8 +26,5 @@ internal interface PerfMonitorOverlayManager {
1926
public fun reset()
2027

2128
/** Update the state of the Perf Monitor overlay. */
22-
public fun update(
23-
interactionName: String,
24-
durationMs: Int,
25-
)
29+
public fun update(data: PerfMonitorUpdateData)
2630
}

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ internal interface PerfMonitorV2Handler {
1616
/** [Experimental] Update the V2 Perf Monitor overlay with the given data. */
1717
// FIXME(T233950466): Refactor ReactHostImpl/DevSupport setup to avoid this public API addition
1818
public fun unstable_updatePerfMonitor(
19-
interactionName: String,
19+
eventName: String,
2020
durationMs: Int,
21+
responsivenessScore: Int,
22+
ttl: Int,
2123
)
2224
}

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -420,9 +420,14 @@ public class ReactHostImpl(
420420
}
421421

422422
@DoNotStrip
423-
private fun unstable_updatePerfMonitor(interactionName: String, durationMs: Int) {
423+
private fun unstable_updatePerfMonitor(
424+
eventName: String,
425+
durationMs: Int,
426+
responsivenessScore: Int,
427+
ttl: Int
428+
) {
424429
if (devSupportManager is PerfMonitorV2Handler) {
425-
devSupportManager.unstable_updatePerfMonitor(interactionName, durationMs)
430+
devSupportManager.unstable_updatePerfMonitor(eventName, durationMs, responsivenessScore, ttl)
426431
}
427432
}
428433

packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JReactHostInspectorTarget.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,10 @@ void JReactHostInspectorTarget::unstable_onPerfMonitorUpdate(
131131
const PerfMonitorUpdateRequest& request) {
132132
if (auto javaReactHostImplStrong = javaReactHostImpl_->get()) {
133133
javaReactHostImplStrong->unstable_updatePerfMonitor(
134-
request.interactionName, request.durationMs);
134+
request.activeInteraction.eventName,
135+
request.activeInteraction.duration,
136+
request.activeInteraction.responsivenessScore,
137+
request.activeInteraction.ttl);
135138
}
136139
}
137140

packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JReactHostInspectorTarget.h

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,19 @@ struct JReactHostImpl : public jni::JavaClass<JReactHostImpl> {
4040

4141
void unstable_updatePerfMonitor(
4242
const std::string& interactionName,
43-
uint16_t durationMs) {
43+
uint16_t durationMs,
44+
jsinspector_modern::InteractionResponsivenessScore responsivenessScore,
45+
uint16_t ttl) {
4446
static auto method =
45-
javaClassStatic()->getMethod<void(jni::local_ref<jni::JString>, jint)>(
46-
"unstable_updatePerfMonitor");
47-
method(self(), jni::make_jstring(interactionName), durationMs);
47+
javaClassStatic()
48+
->getMethod<void(jni::local_ref<jni::JString>, jint, jint, jint)>(
49+
"unstable_updatePerfMonitor");
50+
method(
51+
self(),
52+
jni::make_jstring(interactionName),
53+
durationMs,
54+
static_cast<jint>(responsivenessScore),
55+
ttl);
4856
}
4957

5058
jni::local_ref<jni::JMap<jstring, jstring>> getHostMetadata() const {
@@ -94,7 +102,7 @@ class JReactHostInspectorTarget
94102
void onSetPausedInDebuggerMessage(
95103
const OverlaySetPausedInDebuggerMessageRequest& request) override;
96104
void unstable_onPerfMonitorUpdate(
97-
const PerfMonitorUpdateRequest& request) override;
105+
const jsinspector_modern::PerfMonitorUpdateRequest& request) override;
98106
void loadNetworkResource(
99107
const jsinspector_modern::LoadNetworkResourceRequest& params,
100108
jsinspector_modern::ScopedExecutor<

packages/react-native/ReactCommon/jsinspector-modern/HostTarget.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -272,15 +272,13 @@ void HostTarget::sendCommand(HostCommand command) {
272272
}
273273

274274
void HostTarget::installPerfMetricsBinding() {
275+
perfMonitorUpdateHandler_ =
276+
std::make_unique<PerfMonitorUpdateHandler>(delegate_);
275277
perfMetricsBinding_ = std::make_unique<HostRuntimeBinding>(
276278
*this, // Used immediately
277279
"__chromium_devtools_metrics_reporter",
278280
[this](const std::string& message) {
279-
auto payload = folly::parseJson(message);
280-
HostTargetDelegate::PerfMonitorUpdateRequest request{
281-
.interactionName = payload["eventName"].asString(),
282-
.durationMs = static_cast<uint16_t>(payload["duration"].asInt())};
283-
delegate_.unstable_onPerfMonitorUpdate(request);
281+
perfMonitorUpdateHandler_->handlePerfMetricsUpdate(message);
284282
});
285283
}
286284

packages/react-native/ReactCommon/jsinspector-modern/HostTarget.h

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "InspectorInterfaces.h"
1313
#include "InstanceTarget.h"
1414
#include "NetworkIOAgent.h"
15+
#include "PerfMonitorV2.h"
1516
#include "ScopedExecutor.h"
1617
#include "WeakList.h"
1718

@@ -98,11 +99,6 @@ class HostTargetDelegate : public LoadNetworkResourceDelegate {
9899
}
99100
};
100101

101-
struct PerfMonitorUpdateRequest {
102-
std::string interactionName;
103-
uint16_t durationMs;
104-
};
105-
106102
virtual ~HostTargetDelegate() override;
107103

108104
/**
@@ -309,6 +305,7 @@ class JSINSPECTOR_EXPORT HostTarget
309305
std::shared_ptr<ExecutionContextManager> executionContextManager_;
310306
std::shared_ptr<InstanceTarget> currentInstance_{nullptr};
311307
std::unique_ptr<HostCommandSender> commandSender_;
308+
std::unique_ptr<PerfMonitorUpdateHandler> perfMonitorUpdateHandler_;
312309
std::unique_ptr<HostRuntimeBinding> perfMetricsBinding_;
313310

314311
/**

0 commit comments

Comments
 (0)