mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Switch Perf Monitor metric to Long Tasks (#53297)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/53297 Pivots our display metric for the V2 Perf Monitor experiment by switching to Long Tasks. - Implements a new "__ReactNative__LongTask" metrics event (note: prefixed, since this sits outside the Web Vitals spec). Changelog: [Internal] Reviewed By: mdvacca Differential Revision: D79556595 fbshipit-source-id: 239cf44884f67bf62295b92e2262ae1811d17e4a
This commit is contained in:
committed by
Facebook GitHub Bot
parent
70d5c97ab4
commit
62b8a7b4ef
@@ -2031,7 +2031,7 @@ public abstract class com/facebook/react/devsupport/DevSupportManagerBase : com/
|
||||
public fun startInspector ()V
|
||||
public fun stopInspector ()V
|
||||
public fun toggleElementInspector ()V
|
||||
public fun unstable_updatePerfMonitor (Ljava/lang/String;III)V
|
||||
public fun unstable_updatePerfMonitor (III)V
|
||||
}
|
||||
|
||||
public abstract interface class com/facebook/react/devsupport/DevSupportManagerBase$CallbackWithBundleLoader {
|
||||
|
||||
+2
-8
@@ -937,18 +937,12 @@ public abstract class DevSupportManagerBase(
|
||||
}
|
||||
|
||||
override fun unstable_updatePerfMonitor(
|
||||
eventName: String,
|
||||
durationMs: Int,
|
||||
longTaskDuration: Int,
|
||||
responsivenessScore: Int,
|
||||
ttl: Int,
|
||||
) {
|
||||
perfMonitorOverlayManager?.update(
|
||||
PerfMonitorOverlayManager.PerfMonitorUpdateData(
|
||||
eventName,
|
||||
durationMs,
|
||||
responsivenessScore,
|
||||
ttl,
|
||||
)
|
||||
PerfMonitorOverlayManager.PerfMonitorUpdateData(longTaskDuration, responsivenessScore, ttl)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+3
-4
@@ -39,7 +39,6 @@ internal class PerfMonitorOverlayViewManager(
|
||||
private var hasInteractionData: Boolean = false
|
||||
private var interactionDialog: Dialog? = null
|
||||
private var buttonDialog: Dialog? = null
|
||||
private var interactionNameLabel: TextView? = null
|
||||
private var durationLabel: TextView? = null
|
||||
private var ttl: Int = 0
|
||||
private var hideAfterTimeoutHandler: Handler? = null
|
||||
@@ -70,7 +69,6 @@ internal class PerfMonitorOverlayViewManager(
|
||||
override fun update(data: PerfMonitorOverlayManager.PerfMonitorUpdateData) {
|
||||
UiThreadUtil.runOnUiThread {
|
||||
ensureInitialized()
|
||||
interactionNameLabel?.text = data.eventName
|
||||
durationLabel?.text = String.format(Locale.US, "%d ms", data.durationMs)
|
||||
durationLabel?.setTextColor(getDurationHighlightColor(data.responsivenessScore))
|
||||
hasInteractionData = true
|
||||
@@ -115,9 +113,10 @@ internal class PerfMonitorOverlayViewManager(
|
||||
|
||||
private fun createDialog(context: Context) {
|
||||
val containerLayout = createInnerLayout(context)
|
||||
interactionNameLabel =
|
||||
val longTaskLabel =
|
||||
TextView(context).apply {
|
||||
textSize = TEXT_SIZE_PRIMARY
|
||||
text = "Long Task"
|
||||
setTextColor(Color.WHITE)
|
||||
typeface = TYPEFACE_BOLD
|
||||
}
|
||||
@@ -127,7 +126,7 @@ internal class PerfMonitorOverlayViewManager(
|
||||
setTextColor(COLOR_TEXT_GREEN)
|
||||
typeface = TYPEFACE_BOLD
|
||||
}
|
||||
containerLayout.addView(interactionNameLabel)
|
||||
containerLayout.addView(longTaskLabel)
|
||||
containerLayout.addView(durationLabel)
|
||||
|
||||
val dialog =
|
||||
|
||||
+1
-6
@@ -9,12 +9,7 @@ package com.facebook.react.devsupport.interfaces
|
||||
|
||||
/** [Experimental] Interface to manage the V2 Perf Monitor overlay. */
|
||||
internal interface PerfMonitorOverlayManager {
|
||||
data class PerfMonitorUpdateData(
|
||||
val eventName: String,
|
||||
val durationMs: Int,
|
||||
val responsivenessScore: Int,
|
||||
val ttl: Int,
|
||||
)
|
||||
data class PerfMonitorUpdateData(val durationMs: Int, val responsivenessScore: Int, val ttl: Int)
|
||||
|
||||
/** Enable the Perf Monitor overlay. Will be shown when updates are received. */
|
||||
public fun enable()
|
||||
|
||||
+1
-2
@@ -16,8 +16,7 @@ internal interface PerfMonitorV2Handler {
|
||||
/** [Experimental] Update the V2 Perf Monitor overlay with the given data. */
|
||||
// FIXME(T233950466): Refactor ReactHostImpl/DevSupport setup to avoid this public API addition
|
||||
public fun unstable_updatePerfMonitor(
|
||||
eventName: String,
|
||||
durationMs: Int,
|
||||
longTaskDuration: Int,
|
||||
responsivenessScore: Int,
|
||||
ttl: Int,
|
||||
)
|
||||
|
||||
+2
-3
@@ -421,13 +421,12 @@ public class ReactHostImpl(
|
||||
|
||||
@DoNotStrip
|
||||
private fun unstable_updatePerfMonitor(
|
||||
eventName: String,
|
||||
durationMs: Int,
|
||||
longTaskDuration: Int,
|
||||
responsivenessScore: Int,
|
||||
ttl: Int,
|
||||
) {
|
||||
if (devSupportManager is PerfMonitorV2Handler) {
|
||||
devSupportManager.unstable_updatePerfMonitor(eventName, durationMs, responsivenessScore, ttl)
|
||||
devSupportManager.unstable_updatePerfMonitor(longTaskDuration, responsivenessScore, ttl)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-1
@@ -131,7 +131,6 @@ void JReactHostInspectorTarget::unstable_onPerfMonitorUpdate(
|
||||
const PerfMonitorUpdateRequest& request) {
|
||||
if (auto javaReactHostImplStrong = javaReactHostImpl_->get()) {
|
||||
javaReactHostImplStrong->unstable_updatePerfMonitor(
|
||||
request.activeInteraction.eventName,
|
||||
request.activeInteraction.duration,
|
||||
request.activeInteraction.responsivenessScore,
|
||||
request.activeInteraction.ttl);
|
||||
|
||||
+4
-11
@@ -39,20 +39,13 @@ struct JReactHostImpl : public jni::JavaClass<JReactHostImpl> {
|
||||
}
|
||||
|
||||
void unstable_updatePerfMonitor(
|
||||
const std::string& interactionName,
|
||||
uint16_t durationMs,
|
||||
uint16_t longTaskDuration,
|
||||
jsinspector_modern::InteractionResponsivenessScore responsivenessScore,
|
||||
uint16_t ttl) {
|
||||
static auto method =
|
||||
javaClassStatic()
|
||||
->getMethod<void(jni::local_ref<jni::JString>, jint, jint, jint)>(
|
||||
"unstable_updatePerfMonitor");
|
||||
static auto method = javaClassStatic()->getMethod<void(jint, jint, jint)>(
|
||||
"unstable_updatePerfMonitor");
|
||||
method(
|
||||
self(),
|
||||
jni::make_jstring(interactionName),
|
||||
durationMs,
|
||||
static_cast<jint>(responsivenessScore),
|
||||
ttl);
|
||||
self(), longTaskDuration, static_cast<jint>(responsivenessScore), ttl);
|
||||
}
|
||||
|
||||
jni::local_ref<jni::JMap<jstring, jstring>> getHostMetadata() const {
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace facebook::react::jsinspector_modern {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr uint16_t MIN_DURATION = 10;
|
||||
constexpr uint16_t MIN_DURATION = 200;
|
||||
constexpr uint16_t DEFAULT_TTL = 4000;
|
||||
constexpr uint16_t BAD_EVENT_TTL = 20000;
|
||||
|
||||
@@ -39,6 +39,10 @@ void PerfMonitorUpdateHandler::handlePerfMetricsUpdate(
|
||||
auto payload = folly::parseJson(message);
|
||||
|
||||
if (payload.isObject()) {
|
||||
if (payload["name"] != "__ReactNative__LongTask") {
|
||||
return;
|
||||
}
|
||||
|
||||
auto duration = static_cast<uint16_t>(payload["duration"].asInt());
|
||||
|
||||
if (duration < MIN_DURATION) {
|
||||
@@ -50,36 +54,34 @@ void PerfMonitorUpdateHandler::handlePerfMetricsUpdate(
|
||||
? BAD_EVENT_TTL
|
||||
: DEFAULT_TTL;
|
||||
|
||||
InteractionPayload newInteraction{
|
||||
payload["eventName"].asString(),
|
||||
LongTaskPayload newEvent{
|
||||
static_cast<uint16_t>(payload["startTime"].asInt()),
|
||||
duration,
|
||||
responsivenessScore,
|
||||
ttl};
|
||||
|
||||
if (shouldOverrideLastInteraction(newInteraction)) {
|
||||
lastInteraction_ = newInteraction;
|
||||
if (shouldOverrideLastEvent(newEvent)) {
|
||||
lastEvent_ = newEvent;
|
||||
delegate_.unstable_onPerfMonitorUpdate(
|
||||
PerfMonitorUpdateRequest{newInteraction});
|
||||
PerfMonitorUpdateRequest{newEvent});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool PerfMonitorUpdateHandler::shouldOverrideLastInteraction(
|
||||
const InteractionPayload& newInteraction) {
|
||||
if (!lastInteraction_) {
|
||||
bool PerfMonitorUpdateHandler::shouldOverrideLastEvent(
|
||||
const LongTaskPayload& newEvent) {
|
||||
if (!lastEvent_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Override if last event has expired
|
||||
if (HighResTimeStamp::now().toDOMHighResTimeStamp() >
|
||||
lastInteraction_->startTime + lastInteraction_->ttl) {
|
||||
lastEvent_->startTime + lastEvent_->ttl) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Override if same or greater responsiveness score
|
||||
if (newInteraction.responsivenessScore >=
|
||||
lastInteraction_->responsivenessScore) {
|
||||
if (newEvent.responsivenessScore >= lastEvent_->responsivenessScore) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,8 +24,7 @@ enum class InteractionResponsivenessScore : int32_t {
|
||||
Poor = 2
|
||||
};
|
||||
|
||||
struct InteractionPayload {
|
||||
std::string eventName;
|
||||
struct LongTaskPayload {
|
||||
uint16_t startTime;
|
||||
uint16_t duration;
|
||||
InteractionResponsivenessScore responsivenessScore;
|
||||
@@ -33,7 +32,7 @@ struct InteractionPayload {
|
||||
};
|
||||
|
||||
struct PerfMonitorUpdateRequest {
|
||||
InteractionPayload activeInteraction;
|
||||
LongTaskPayload activeInteraction;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -42,7 +41,7 @@ struct PerfMonitorUpdateRequest {
|
||||
*/
|
||||
class PerfMonitorUpdateHandler {
|
||||
public:
|
||||
PerfMonitorUpdateHandler(HostTargetDelegate& delegate)
|
||||
explicit PerfMonitorUpdateHandler(HostTargetDelegate& delegate)
|
||||
: delegate_(delegate) {}
|
||||
|
||||
/**
|
||||
@@ -52,9 +51,9 @@ class PerfMonitorUpdateHandler {
|
||||
|
||||
private:
|
||||
HostTargetDelegate& delegate_;
|
||||
std::optional<InteractionPayload> lastInteraction_;
|
||||
std::optional<LongTaskPayload> lastEvent_;
|
||||
|
||||
bool shouldOverrideLastInteraction(const InteractionPayload& newInteraction);
|
||||
bool shouldOverrideLastEvent(const LongTaskPayload& newInteraction);
|
||||
};
|
||||
|
||||
} // namespace facebook::react::jsinspector_modern
|
||||
|
||||
@@ -72,4 +72,27 @@ void CdpMetricsReporter::onEventTimingEntry(
|
||||
});
|
||||
}
|
||||
|
||||
void CdpMetricsReporter::onLongTaskEntry(
|
||||
const PerformanceLongTaskTiming& entry) {
|
||||
runtimeExecutor_([entry = std::move(entry)](jsi::Runtime& runtime) {
|
||||
auto global = runtime.global();
|
||||
if (!global.hasProperty(runtime, metricsReporterName.data())) {
|
||||
return;
|
||||
}
|
||||
|
||||
folly::dynamic jsonPayload = folly::dynamic::object;
|
||||
jsonPayload["name"] = "__ReactNative__LongTask";
|
||||
jsonPayload["duration"] =
|
||||
static_cast<int>(entry.duration.toDOMHighResTimeStamp());
|
||||
jsonPayload["startTime"] =
|
||||
static_cast<int>(entry.startTime.toDOMHighResTimeStamp());
|
||||
|
||||
auto jsonString = folly::toJson(jsonPayload);
|
||||
auto jsiString = jsi::String::createFromUtf8(runtime, jsonString);
|
||||
auto metricsReporter =
|
||||
global.getPropertyAsFunction(runtime, metricsReporterName.data());
|
||||
metricsReporter.call(runtime, jsiString);
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace facebook::react
|
||||
|
||||
@@ -28,6 +28,7 @@ class CdpMetricsReporter : public PerformanceEntryReporterEventTimingListener {
|
||||
explicit CdpMetricsReporter(RuntimeExecutor runtimeExecutor);
|
||||
|
||||
void onEventTimingEntry(const PerformanceEventTiming& entry) override;
|
||||
void onLongTaskEntry(const PerformanceLongTaskTiming& entry) override;
|
||||
|
||||
private:
|
||||
const RuntimeExecutor runtimeExecutor_{};
|
||||
|
||||
+10
@@ -297,6 +297,16 @@ void PerformanceEntryReporter::reportLongTask(
|
||||
}
|
||||
|
||||
observerRegistry_->queuePerformanceEntry(entry);
|
||||
|
||||
std::vector<PerformanceEntryReporterEventTimingListener*> listenersCopy;
|
||||
{
|
||||
std::shared_lock lock(listenersMutex_);
|
||||
listenersCopy = eventTimingListeners_;
|
||||
}
|
||||
|
||||
for (auto* listener : listenersCopy) {
|
||||
listener->onLongTaskEntry(entry);
|
||||
}
|
||||
}
|
||||
|
||||
void PerformanceEntryReporter::reportResourceTiming(
|
||||
|
||||
+3
-1
@@ -18,7 +18,9 @@ class PerformanceEntryReporterEventTimingListener {
|
||||
public:
|
||||
virtual ~PerformanceEntryReporterEventTimingListener() = default;
|
||||
|
||||
virtual void onEventTimingEntry(const PerformanceEventTiming& entry) = 0;
|
||||
virtual void onEventTimingEntry(const PerformanceEventTiming& /*entry*/) {}
|
||||
|
||||
virtual void onLongTaskEntry(const PerformanceLongTaskTiming& /*entry*/) {}
|
||||
};
|
||||
|
||||
} // namespace facebook::react
|
||||
|
||||
Reference in New Issue
Block a user