mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Implement Kotlin API for PerformanceTracer in RNDT (#54316)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/54316 Changelog: [internal] This defines an internal class in Kotlin to access `PerformanceTracer` methods, necessary for platform-specific integrations on Android. Reviewed By: sbuggay Differential Revision: D85689126 fbshipit-source-id: 84cb675984b90c677c3a322b191e24cc6b58c74f
This commit is contained in:
committed by
meta-codesync[bot]
parent
712c544be6
commit
b68329f7ca
+109
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.react.internal.tracing
|
||||
|
||||
import com.facebook.proguard.annotations.DoNotStrip
|
||||
import com.facebook.react.bridge.ReadableNativeMap
|
||||
import com.facebook.soloader.SoLoader
|
||||
|
||||
/**
|
||||
* JNI interface to access PerformanceTracer methods from React Native Inspector Modern.
|
||||
*
|
||||
* This provides access to reportMark and reportMeasure methods which are used for performance
|
||||
* tracing in the React Native DevTools.
|
||||
*/
|
||||
@DoNotStrip
|
||||
public object PerformanceTracer {
|
||||
init {
|
||||
SoLoader.loadLibrary("react_performancetracerjni")
|
||||
}
|
||||
|
||||
/** Callback interface for tracing state changes. */
|
||||
@DoNotStrip
|
||||
public interface TracingStateCallback {
|
||||
/**
|
||||
* Called when tracing state changes.
|
||||
*
|
||||
* @param isTracing true if tracing has started, false if tracing has stopped
|
||||
*/
|
||||
@DoNotStrip public fun onTracingStateChanged(isTracing: Boolean)
|
||||
}
|
||||
|
||||
/**
|
||||
* Report a Performance.mark() event - a labelled timestamp.
|
||||
*
|
||||
* @param name The name/label of the mark
|
||||
* @param timestampNanos The timestamp in nanoseconds (monotonic time)
|
||||
* @param detail Optional map with additional detail (pass null if not needed)
|
||||
*/
|
||||
@DoNotStrip
|
||||
@JvmStatic
|
||||
public external fun reportMark(name: String, timestampNanos: Long, detail: ReadableNativeMap?)
|
||||
|
||||
/**
|
||||
* Report a Performance.measure() event - a labelled duration.
|
||||
*
|
||||
* @param name The name/label of the measure
|
||||
* @param startTimestampNanos The start timestamp in nanoseconds (monotonic time)
|
||||
* @param durationNanos The duration in nanoseconds
|
||||
* @param detail Optional map with additional detail (pass null if not needed)
|
||||
*/
|
||||
@DoNotStrip
|
||||
@JvmStatic
|
||||
public external fun reportMeasure(
|
||||
name: String,
|
||||
startTimestampNanos: Long,
|
||||
durationNanos: Long,
|
||||
detail: ReadableNativeMap?,
|
||||
)
|
||||
|
||||
/**
|
||||
* Report a TimeStamp Trace Event - a labelled entry on Performance timeline.
|
||||
*
|
||||
* @param name The name/label of the timestamp
|
||||
* @param startTimeNanos Start timestamp in nanoseconds (monotonic time)
|
||||
* @param endTimeNanos End timestamp in nanoseconds (monotonic time)
|
||||
* @param trackName Optional track name for organizing the timestamp
|
||||
* @param trackGroup Optional track group for organizing the timestamp
|
||||
* @param color Optional color name (e.g., "primary", "secondary", "error", "warning")
|
||||
*/
|
||||
@DoNotStrip
|
||||
@JvmStatic
|
||||
public external fun reportTimeStamp(
|
||||
name: String,
|
||||
startTimeNanos: Long,
|
||||
endTimeNanos: Long,
|
||||
trackName: String?,
|
||||
trackGroup: String?,
|
||||
color: String?,
|
||||
)
|
||||
|
||||
/**
|
||||
* Check if the tracer is currently tracing.
|
||||
*
|
||||
* @return true if tracing is active, false otherwise
|
||||
*/
|
||||
@DoNotStrip @JvmStatic public external fun isTracing(): Boolean
|
||||
|
||||
/**
|
||||
* Subscribe to tracing state changes (start/stop events).
|
||||
*
|
||||
* @param callback The callback to invoke when tracing starts or stops
|
||||
* @return A subscription ID that can be used to unsubscribe
|
||||
*/
|
||||
@DoNotStrip
|
||||
@JvmStatic
|
||||
public external fun subscribeToTracingStateChanges(callback: TracingStateCallback): Int
|
||||
|
||||
/**
|
||||
* Unsubscribe from tracing state changes.
|
||||
*
|
||||
* @param subscriptionId The subscription ID returned from subscribeToTracingStateChanges
|
||||
*/
|
||||
@DoNotStrip @JvmStatic public external fun unsubscribeFromTracingStateChanges(subscriptionId: Int)
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#include "PerformanceTracerCxxInterop.h"
|
||||
|
||||
#include <fbjni/fbjni.h>
|
||||
|
||||
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* /*unused*/) {
|
||||
return facebook::jni::initialize(vm, [] {
|
||||
facebook::react::PerformanceTracerCxxInterop::registerNatives();
|
||||
});
|
||||
}
|
||||
+241
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#include "PerformanceTracerCxxInterop.h"
|
||||
|
||||
#include <folly/dynamic.h>
|
||||
#include <jsinspector-modern/tracing/PerformanceTracer.h>
|
||||
#include <react/jni/NativeMap.h>
|
||||
#include <react/jni/ReadableNativeMap.h>
|
||||
#include <react/timing/primitives.h>
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
void TracingStateCallback::onTracingStateChanged(bool isTracing) const {
|
||||
static const auto method =
|
||||
javaClassStatic()->getMethod<void(jboolean)>("onTracingStateChanged");
|
||||
method(self(), static_cast<jboolean>(isTracing));
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class TracingCallbackRegistry {
|
||||
public:
|
||||
static TracingCallbackRegistry& getInstance() {
|
||||
static TracingCallbackRegistry instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void registerCallback(
|
||||
uint32_t subscriptionId,
|
||||
jni::global_ref<jobject> callback) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
callbacks_[subscriptionId] = std::move(callback);
|
||||
}
|
||||
|
||||
void unregisterCallback(uint32_t subscriptionId) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
callbacks_.erase(subscriptionId);
|
||||
}
|
||||
|
||||
jni::global_ref<jobject> getCallback(uint32_t subscriptionId) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
auto it = callbacks_.find(subscriptionId);
|
||||
if (it != callbacks_.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
std::mutex mutex_;
|
||||
std::map<uint32_t, jni::global_ref<jobject>> callbacks_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
void PerformanceTracerCxxInterop::reportMark(
|
||||
jni::alias_ref<PerformanceTracerCxxInterop> /*jthis*/,
|
||||
jni::alias_ref<jstring> name,
|
||||
jlong timestampNanos,
|
||||
jni::alias_ref<ReadableNativeMap::javaobject> detail) {
|
||||
auto& tracer = jsinspector_modern::tracing::PerformanceTracer::getInstance();
|
||||
|
||||
if (!tracer.isTracing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string nameStr = name->toStdString();
|
||||
HighResTimeStamp timestamp = HighResTimeStamp::fromChronoSteadyClockTimePoint(
|
||||
std::chrono::steady_clock::time_point(
|
||||
std::chrono::nanoseconds(timestampNanos)));
|
||||
|
||||
folly::dynamic detailDynamic = nullptr;
|
||||
if (detail) {
|
||||
detailDynamic = detail->cthis()->consume();
|
||||
}
|
||||
|
||||
tracer.reportMark(nameStr, timestamp, std::move(detailDynamic));
|
||||
}
|
||||
|
||||
void PerformanceTracerCxxInterop::reportMeasure(
|
||||
jni::alias_ref<PerformanceTracerCxxInterop> /*jthis*/,
|
||||
jni::alias_ref<jstring> name,
|
||||
jlong startTimestampNanos,
|
||||
jlong durationNanos,
|
||||
jni::alias_ref<ReadableNativeMap::javaobject> detail) {
|
||||
auto& tracer = jsinspector_modern::tracing::PerformanceTracer::getInstance();
|
||||
|
||||
if (!tracer.isTracing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string nameStr = name->toStdString();
|
||||
HighResTimeStamp startTimestamp =
|
||||
HighResTimeStamp::fromChronoSteadyClockTimePoint(
|
||||
std::chrono::steady_clock::time_point(
|
||||
std::chrono::nanoseconds(startTimestampNanos)));
|
||||
HighResDuration duration = HighResDuration::fromNanoseconds(durationNanos);
|
||||
|
||||
folly::dynamic detailDynamic = nullptr;
|
||||
if (detail) {
|
||||
detailDynamic = detail->cthis()->consume();
|
||||
}
|
||||
|
||||
tracer.reportMeasure(
|
||||
nameStr, startTimestamp, duration, std::move(detailDynamic));
|
||||
}
|
||||
|
||||
void PerformanceTracerCxxInterop::reportTimeStamp(
|
||||
jni::alias_ref<PerformanceTracerCxxInterop> /*jthis*/,
|
||||
jni::alias_ref<jstring> name,
|
||||
jlong startTimeNanos,
|
||||
jlong endTimeNanos,
|
||||
jni::alias_ref<jstring> trackName,
|
||||
jni::alias_ref<jstring> trackGroup,
|
||||
jni::alias_ref<jstring> color) {
|
||||
auto& tracer = jsinspector_modern::tracing::PerformanceTracer::getInstance();
|
||||
|
||||
if (!tracer.isTracing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string nameStr = name->toStdString();
|
||||
|
||||
// Convert start timestamp
|
||||
HighResTimeStamp startTimestamp =
|
||||
HighResTimeStamp::fromChronoSteadyClockTimePoint(
|
||||
std::chrono::steady_clock::time_point(
|
||||
std::chrono::nanoseconds(startTimeNanos)));
|
||||
|
||||
// Convert end timestamp
|
||||
HighResTimeStamp endTimestamp =
|
||||
HighResTimeStamp::fromChronoSteadyClockTimePoint(
|
||||
std::chrono::steady_clock::time_point(
|
||||
std::chrono::nanoseconds(endTimeNanos)));
|
||||
|
||||
// Handle optional string parameters
|
||||
std::optional<std::string> trackNameOpt = std::nullopt;
|
||||
if (trackName) {
|
||||
trackNameOpt = trackName->toStdString();
|
||||
}
|
||||
|
||||
std::optional<std::string> trackGroupOpt = std::nullopt;
|
||||
if (trackGroup) {
|
||||
trackGroupOpt = trackGroup->toStdString();
|
||||
}
|
||||
|
||||
// Handle optional color parameter
|
||||
std::optional<jsinspector_modern::tracing::ConsoleTimeStampColor> colorOpt =
|
||||
std::nullopt;
|
||||
if (color) {
|
||||
colorOpt = jsinspector_modern::tracing::getConsoleTimeStampColorFromString(
|
||||
color->toStdString());
|
||||
}
|
||||
|
||||
tracer.reportTimeStamp(
|
||||
nameStr,
|
||||
startTimestamp,
|
||||
endTimestamp,
|
||||
trackNameOpt,
|
||||
trackGroupOpt,
|
||||
colorOpt);
|
||||
}
|
||||
|
||||
jboolean PerformanceTracerCxxInterop::isTracing(
|
||||
jni::alias_ref<PerformanceTracerCxxInterop> /*jthis*/) {
|
||||
return static_cast<jboolean>(
|
||||
jsinspector_modern::tracing::PerformanceTracer::getInstance()
|
||||
.isTracing());
|
||||
}
|
||||
|
||||
jint PerformanceTracerCxxInterop::subscribeToTracingStateChanges(
|
||||
jni::alias_ref<PerformanceTracerCxxInterop> /*jthis*/,
|
||||
jni::alias_ref<TracingStateCallback::javaobject> callback) {
|
||||
auto globalCallback = jni::make_global(callback);
|
||||
|
||||
auto& tracer = jsinspector_modern::tracing::PerformanceTracer::getInstance();
|
||||
|
||||
auto callbackWrapper = std::make_shared<uint32_t>(0);
|
||||
|
||||
uint32_t subscriptionId =
|
||||
tracer.subscribeToTracingStateChanges([callbackWrapper](bool isTracing) {
|
||||
auto callback = TracingCallbackRegistry::getInstance().getCallback(
|
||||
*callbackWrapper);
|
||||
if (callback) {
|
||||
try {
|
||||
jni::ThreadScope::WithClassLoader([&] {
|
||||
auto callbackClass = callback->getClass();
|
||||
auto onTracingStateChangedMethod =
|
||||
callbackClass->getMethod<void(jboolean)>(
|
||||
"onTracingStateChanged");
|
||||
onTracingStateChangedMethod(
|
||||
callback, static_cast<jboolean>(isTracing));
|
||||
});
|
||||
} catch (const std::exception& e) {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
*callbackWrapper = subscriptionId;
|
||||
TracingCallbackRegistry::getInstance().registerCallback(
|
||||
subscriptionId, globalCallback);
|
||||
|
||||
return static_cast<jint>(subscriptionId);
|
||||
}
|
||||
|
||||
void PerformanceTracerCxxInterop::unsubscribeFromTracingStateChanges(
|
||||
jni::alias_ref<PerformanceTracerCxxInterop> /*jthis*/,
|
||||
jint subscriptionId) {
|
||||
auto& tracer = jsinspector_modern::tracing::PerformanceTracer::getInstance();
|
||||
tracer.unsubscribeFromTracingStateChanges(
|
||||
static_cast<uint32_t>(subscriptionId));
|
||||
TracingCallbackRegistry::getInstance().unregisterCallback(
|
||||
static_cast<uint32_t>(subscriptionId));
|
||||
}
|
||||
|
||||
void PerformanceTracerCxxInterop::registerNatives() {
|
||||
javaClassLocal()->registerNatives(
|
||||
{makeNativeMethod("reportMark", PerformanceTracerCxxInterop::reportMark),
|
||||
makeNativeMethod(
|
||||
"reportMeasure", PerformanceTracerCxxInterop::reportMeasure),
|
||||
makeNativeMethod(
|
||||
"reportTimeStamp", PerformanceTracerCxxInterop::reportTimeStamp),
|
||||
makeNativeMethod("isTracing", PerformanceTracerCxxInterop::isTracing),
|
||||
makeNativeMethod(
|
||||
"subscribeToTracingStateChanges",
|
||||
PerformanceTracerCxxInterop::subscribeToTracingStateChanges),
|
||||
makeNativeMethod(
|
||||
"unsubscribeFromTracingStateChanges",
|
||||
PerformanceTracerCxxInterop::unsubscribeFromTracingStateChanges)});
|
||||
}
|
||||
|
||||
} // namespace facebook::react
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <fbjni/fbjni.h>
|
||||
#include <jni.h>
|
||||
#include <react/jni/ReadableNativeMap.h>
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
class TracingStateCallback : public facebook::jni::JavaClass<TracingStateCallback> {
|
||||
public:
|
||||
static constexpr auto kJavaDescriptor =
|
||||
"Lcom/facebook/react/internal/tracing/PerformanceTracer$TracingStateCallback;";
|
||||
|
||||
void onTracingStateChanged(bool isTracing) const;
|
||||
};
|
||||
|
||||
class PerformanceTracerCxxInterop : public facebook::jni::JavaClass<PerformanceTracerCxxInterop> {
|
||||
public:
|
||||
static constexpr auto kJavaDescriptor = "Lcom/facebook/react/internal/tracing/PerformanceTracer;";
|
||||
|
||||
static void reportMark(
|
||||
facebook::jni::alias_ref<PerformanceTracerCxxInterop> jthis,
|
||||
facebook::jni::alias_ref<jstring> name,
|
||||
jlong timestampNanos,
|
||||
facebook::jni::alias_ref<ReadableNativeMap::javaobject> detail);
|
||||
|
||||
static void reportMeasure(
|
||||
facebook::jni::alias_ref<PerformanceTracerCxxInterop> jthis,
|
||||
facebook::jni::alias_ref<jstring> name,
|
||||
jlong startTimestampNanos,
|
||||
jlong durationNanos,
|
||||
facebook::jni::alias_ref<ReadableNativeMap::javaobject> detail);
|
||||
|
||||
static void reportTimeStamp(
|
||||
facebook::jni::alias_ref<PerformanceTracerCxxInterop> jthis,
|
||||
facebook::jni::alias_ref<jstring> name,
|
||||
jlong startTimeNanos,
|
||||
jlong endTimeNanos,
|
||||
facebook::jni::alias_ref<jstring> trackName,
|
||||
facebook::jni::alias_ref<jstring> trackGroup,
|
||||
facebook::jni::alias_ref<jstring> color);
|
||||
|
||||
static jboolean isTracing(facebook::jni::alias_ref<PerformanceTracerCxxInterop> jthis);
|
||||
|
||||
static jint subscribeToTracingStateChanges(
|
||||
facebook::jni::alias_ref<PerformanceTracerCxxInterop> jthis,
|
||||
facebook::jni::alias_ref<TracingStateCallback::javaobject> callback);
|
||||
|
||||
static void unsubscribeFromTracingStateChanges(
|
||||
facebook::jni::alias_ref<PerformanceTracerCxxInterop> jthis,
|
||||
jint subscriptionId);
|
||||
|
||||
static void registerNatives();
|
||||
};
|
||||
|
||||
} // namespace facebook::react
|
||||
Reference in New Issue
Block a user