diff --git a/packages/react-native/Libraries/WebPerformance/NativePerformance.cpp b/packages/react-native/Libraries/WebPerformance/NativePerformance.cpp index f2ec308fda0267..eae5c68b464cdb 100644 --- a/packages/react-native/Libraries/WebPerformance/NativePerformance.cpp +++ b/packages/react-native/Libraries/WebPerformance/NativePerformance.cpp @@ -56,17 +56,21 @@ std::unordered_map NativePerformance::getSimpleMemoryInfo( ReactNativeStartupTiming NativePerformance::getReactNativeStartupTiming( jsi::Runtime &rt) { - ReactNativeStartupTiming result = {0, 0, 0, 0}; + ReactNativeStartupTiming result = {0, 0, 0, 0, 0, 0}; ReactMarker::StartupLogger &startupLogger = ReactMarker::StartupLogger::getInstance(); result.startTime = startupLogger.getAppStartupStartTime(); + if (result.startTime == 0) { + result.startTime = startupLogger.getInitReactRuntimeStartTime(); + } + result.initializeRuntimeStart = startupLogger.getInitReactRuntimeStartTime(); result.executeJavaScriptBundleEntryPointStart = startupLogger.getRunJSBundleStartTime(); result.executeJavaScriptBundleEntryPointEnd = startupLogger.getRunJSBundleEndTime(); + result.initializeRuntimeEnd = startupLogger.getInitReactRuntimeEndTime(); result.endTime = startupLogger.getAppStartupEndTime(); - return result; } diff --git a/packages/react-native/Libraries/WebPerformance/NativePerformance.h b/packages/react-native/Libraries/WebPerformance/NativePerformance.h index 1726bb663f3f59..3353a94c0f6205 100644 --- a/packages/react-native/Libraries/WebPerformance/NativePerformance.h +++ b/packages/react-native/Libraries/WebPerformance/NativePerformance.h @@ -20,15 +20,18 @@ class PerformanceEntryReporter; using ReactNativeStartupTiming = NativePerformanceCxxBaseReactNativeStartupTiming< - int32_t, // Start time of the RN app startup process - int32_t, // End time of the RN app startup process - int32_t, // Start time that RN app execute the JS bundle - int32_t // End time that RN app execute the JS bundle - >; + int32_t, + int32_t, + int32_t, + int32_t, + int32_t, + int32_t>; template <> struct Bridging : NativePerformanceCxxBaseReactNativeStartupTimingBridging< + int32_t, + int32_t, int32_t, int32_t, int32_t, diff --git a/packages/react-native/Libraries/WebPerformance/NativePerformance.js b/packages/react-native/Libraries/WebPerformance/NativePerformance.js index 092b4ff6875c4b..597d8144862738 100644 --- a/packages/react-native/Libraries/WebPerformance/NativePerformance.js +++ b/packages/react-native/Libraries/WebPerformance/NativePerformance.js @@ -17,6 +17,8 @@ export type NativeMemoryInfo = {[key: string]: number}; export type ReactNativeStartupTiming = {| startTime: number, endTime: number, + initializeRuntimeStart: number, + initializeRuntimeEnd: number, executeJavaScriptBundleEntryPointStart: number, executeJavaScriptBundleEntryPointEnd: number, |}; diff --git a/packages/react-native/Libraries/WebPerformance/ReactNativeStartupTiming.js b/packages/react-native/Libraries/WebPerformance/ReactNativeStartupTiming.js index fbb0fa655d3e93..8258c2b4402446 100644 --- a/packages/react-native/Libraries/WebPerformance/ReactNativeStartupTiming.js +++ b/packages/react-native/Libraries/WebPerformance/ReactNativeStartupTiming.js @@ -21,6 +21,8 @@ export default class ReactNativeStartupTiming { // See https://www.w3.org/TR/performance-timeline/#performancetiming-interface _startTime = 0; _endTime = 0; + _initializeRuntimeStart = 0; + _initializeRuntimeEnd = 0; _executeJavaScriptBundleEntryPointStart = 0; _executeJavaScriptBundleEntryPointEnd = 0; @@ -28,6 +30,8 @@ export default class ReactNativeStartupTiming { if (startUpTiming != null) { this._startTime = startUpTiming.startTime; this._endTime = startUpTiming.endTime; + this._initializeRuntimeStart = startUpTiming.initializeRuntimeStart; + this._initializeRuntimeEnd = startUpTiming.initializeRuntimeEnd; this._executeJavaScriptBundleEntryPointStart = startUpTiming.executeJavaScriptBundleEntryPointStart; this._executeJavaScriptBundleEntryPointEnd = @@ -36,7 +40,7 @@ export default class ReactNativeStartupTiming { } /** - * Start time of the RN app startup process. This is provided by the platform by implementing the `ReactMarker.setAppStartTime` API in the native platform code. + * Start time of the RN app startup process. This is provided by the platform by implementing the `ReactMarker.setAppStartTime` API in the native platform code. */ get startTime(): number { return this._startTime; @@ -49,6 +53,20 @@ export default class ReactNativeStartupTiming { return this._endTime; } + /** + * Start time when RN runtime get initialized. This is when RN infra first kicks in app startup process. + */ + get initializeRuntimeStart(): number { + return this._initializeRuntimeStart; + } + + /** + * End time when RN runtime get initialized. This is the last marker before ends of the app startup process. + */ + get initializeRuntimeEnd(): number { + return this._initializeRuntimeEnd; + } + /** * Start time of JS bundle being executed. This indicates the RN JS bundle is loaded and start to be evaluated. */ diff --git a/packages/react-native/Libraries/WebPerformance/__mocks__/NativePerformance.js b/packages/react-native/Libraries/WebPerformance/__mocks__/NativePerformance.js index b3335e0c774378..ee5eed6e6b0157 100644 --- a/packages/react-native/Libraries/WebPerformance/__mocks__/NativePerformance.js +++ b/packages/react-native/Libraries/WebPerformance/__mocks__/NativePerformance.js @@ -58,6 +58,8 @@ const NativePerformanceMock: NativePerformance = { endTime: 0, executeJavaScriptBundleEntryPointStart: 0, executeJavaScriptBundleEntryPointEnd: 0, + initializeRuntimeStart: 0, + initializeRuntimeEnd: 0, }; }, }; diff --git a/packages/react-native/React/Base/RCTPLTag.h b/packages/react-native/React/Base/RCTPLTag.h index cb9f8f0ded0462..b3ebfb94b4ffe0 100644 --- a/packages/react-native/React/Base/RCTPLTag.h +++ b/packages/react-native/React/Base/RCTPLTag.h @@ -26,5 +26,6 @@ typedef NS_ENUM(NSInteger, RCTPLTag) { RCTPLBundleSize, RCTPLReactInstanceInit, RCTPLAppStartup, + RCTPLInitReactRuntime, RCTPLSize // This is used to count the size }; diff --git a/packages/react-native/React/Base/RCTPerformanceLoggerLabels.m b/packages/react-native/React/Base/RCTPerformanceLoggerLabels.m index c508dbfc39a170..f24ace4e38b8bd 100644 --- a/packages/react-native/React/Base/RCTPerformanceLoggerLabels.m +++ b/packages/react-native/React/Base/RCTPerformanceLoggerLabels.m @@ -51,6 +51,8 @@ return @"ReactInstanceInit"; case RCTPLAppStartup: return @"AppStartup"; + case RCTPLInitReactRuntime: + return @"InitReactRuntime"; case RCTPLSize: // Only used to count enum size RCTAssert(NO, @"RCTPLSize should not be used to track performance timestamps."); return nil; diff --git a/packages/react-native/React/CxxBridge/RCTCxxBridge.mm b/packages/react-native/React/CxxBridge/RCTCxxBridge.mm index 48644afca6c999..af931fd45ca10f 100644 --- a/packages/react-native/React/CxxBridge/RCTCxxBridge.mm +++ b/packages/react-native/React/CxxBridge/RCTCxxBridge.mm @@ -126,6 +126,12 @@ static void mapReactMarkerToPerformanceLogger( case ReactMarker::APP_STARTUP_STOP: [performanceLogger markStopForTag:RCTPLAppStartup]; break; + case ReactMarker::INIT_REACT_RUNTIME_START: + [performanceLogger markStartForTag:RCTPLInitReactRuntime]; + break; + case ReactMarker::INIT_REACT_RUNTIME_STOP: + [performanceLogger markStopForTag:RCTPLInitReactRuntime]; + break; case ReactMarker::RUN_JS_BUNDLE_START: [performanceLogger markStartForTag:RCTPLScriptExecution]; break; diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactNativeHost.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactNativeHost.java index 02c5f834689d25..4e6f41bce8760c 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactNativeHost.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactNativeHost.java @@ -38,6 +38,7 @@ protected ReactNativeHost(Application application) { /** Get the current {@link ReactInstanceManager} instance, or create one. */ public ReactInstanceManager getReactInstanceManager() { if (mReactInstanceManager == null) { + ReactMarker.logMarker(ReactMarkerConstants.INIT_REACT_RUNTIME_START); ReactMarker.logMarker(ReactMarkerConstants.GET_REACT_INSTANCE_MANAGER_START); mReactInstanceManager = createReactInstanceManager(); ReactMarker.logMarker(ReactMarkerConstants.GET_REACT_INSTANCE_MANAGER_END); diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactMarkerConstants.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactMarkerConstants.java index ce4f659698e769..f67168d76db586 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactMarkerConstants.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactMarkerConstants.java @@ -13,6 +13,8 @@ public enum ReactMarkerConstants { APP_STARTUP_END(true), CREATE_REACT_CONTEXT_START, CREATE_REACT_CONTEXT_END(true), + INIT_REACT_RUNTIME_START(true), + INIT_REACT_RUNTIME_END(true), PROCESS_PACKAGES_START, PROCESS_PACKAGES_END, BUILD_NATIVE_MODULE_REGISTRY_START, diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JReactMarker.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JReactMarker.cpp index 59cf545a074833..1e6daf9ba55a2a 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JReactMarker.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JReactMarker.cpp @@ -72,6 +72,12 @@ void JReactMarker::logPerfMarkerWithInstanceKey( case ReactMarker::APP_STARTUP_STOP: JReactMarker::logMarker("APP_STARTUP_END"); break; + case ReactMarker::INIT_REACT_RUNTIME_START: + JReactMarker::logMarker("INIT_REACT_RUNTIME_START"); + break; + case ReactMarker::INIT_REACT_RUNTIME_STOP: + JReactMarker::logMarker("INIT_REACT_RUNTIME_END"); + break; case ReactMarker::RUN_JS_BUNDLE_START: JReactMarker::logMarker("RUN_JS_BUNDLE_START", tag, instanceKey); break; @@ -120,6 +126,12 @@ void JReactMarker::nativeLogMarker( } else if (markerNameStr == "APP_STARTUP_END") { ReactMarker::logMarkerDone( ReactMarker::APP_STARTUP_STOP, (double)markerTime); + } else if (markerNameStr == "INIT_REACT_RUNTIME_START") { + ReactMarker::logMarkerDone( + ReactMarker::INIT_REACT_RUNTIME_START, (double)markerTime); + } else if (markerNameStr == "INIT_REACT_RUNTIME_END") { + ReactMarker::logMarkerDone( + ReactMarker::INIT_REACT_RUNTIME_STOP, (double)markerTime); } else if (markerNameStr == "RUN_JS_BUNDLE_START") { ReactMarker::logMarkerDone( ReactMarker::RUN_JS_BUNDLE_START, (double)markerTime); diff --git a/packages/react-native/ReactCommon/cxxreact/ReactMarker.cpp b/packages/react-native/ReactCommon/cxxreact/ReactMarker.cpp index 2b6478b33c677e..e2e730012eaead 100644 --- a/packages/react-native/ReactCommon/cxxreact/ReactMarker.cpp +++ b/packages/react-native/ReactCommon/cxxreact/ReactMarker.cpp @@ -64,6 +64,18 @@ void StartupLogger::logStartupEvent( } return; + case ReactMarkerId::INIT_REACT_RUNTIME_START: + if (initReactRuntimeStartTime == 0) { + initReactRuntimeStartTime = markerTime; + } + return; + + case ReactMarkerId::INIT_REACT_RUNTIME_STOP: + if (initReactRuntimeEndTime == 0) { + initReactRuntimeEndTime = markerTime; + } + return; + case ReactMarkerId::RUN_JS_BUNDLE_START: if (runJSBundleStartTime == 0) { runJSBundleStartTime = markerTime; @@ -85,6 +97,14 @@ double StartupLogger::getAppStartupStartTime() { return appStartupStartTime; } +double StartupLogger::getInitReactRuntimeStartTime() { + return initReactRuntimeStartTime; +} + +double StartupLogger::getInitReactRuntimeEndTime() { + return initReactRuntimeEndTime; +} + double StartupLogger::getRunJSBundleStartTime() { return runJSBundleStartTime; } diff --git a/packages/react-native/ReactCommon/cxxreact/ReactMarker.h b/packages/react-native/ReactCommon/cxxreact/ReactMarker.h index 98e51b978916f1..c8612f7c2c17ef 100644 --- a/packages/react-native/ReactCommon/cxxreact/ReactMarker.h +++ b/packages/react-native/ReactCommon/cxxreact/ReactMarker.h @@ -17,6 +17,8 @@ namespace ReactMarker { enum ReactMarkerId { APP_STARTUP_START, APP_STARTUP_STOP, + INIT_REACT_RUNTIME_START, + INIT_REACT_RUNTIME_STOP, NATIVE_REQUIRE_START, NATIVE_REQUIRE_STOP, RUN_JS_BUNDLE_START, @@ -71,6 +73,8 @@ class RN_EXPORT StartupLogger { void logStartupEvent(const ReactMarkerId markerName, double markerTime); double getAppStartupStartTime(); + double getInitReactRuntimeStartTime(); + double getInitReactRuntimeEndTime(); double getRunJSBundleStartTime(); double getRunJSBundleEndTime(); double getAppStartupEndTime(); @@ -82,6 +86,8 @@ class RN_EXPORT StartupLogger { double appStartupStartTime; double appStartupEndTime; + double initReactRuntimeStartTime; + double initReactRuntimeEndTime; double runJSBundleStartTime; double runJSBundleEndTime; }; diff --git a/packages/react-native/ReactCommon/jsiexecutor/jsireact/JSIExecutor.cpp b/packages/react-native/ReactCommon/jsiexecutor/jsireact/JSIExecutor.cpp index 03d189e5fa0148..59898a1798df05 100644 --- a/packages/react-native/ReactCommon/jsiexecutor/jsireact/JSIExecutor.cpp +++ b/packages/react-native/ReactCommon/jsiexecutor/jsireact/JSIExecutor.cpp @@ -163,6 +163,8 @@ void JSIExecutor::loadBundle( if (hasLogger) { ReactMarker::logTaggedMarker( ReactMarker::RUN_JS_BUNDLE_STOP, scriptName.c_str()); + ReactMarker::logMarker(ReactMarker::INIT_REACT_RUNTIME_STOP); + ReactMarker::logMarker(ReactMarker::APP_STARTUP_STOP); } } diff --git a/packages/react-native/ReactCommon/react/bridgeless/ReactInstance.cpp b/packages/react-native/ReactCommon/react/bridgeless/ReactInstance.cpp index 68c2bf706a65c0..4ece09a687060f 100644 --- a/packages/react-native/ReactCommon/react/bridgeless/ReactInstance.cpp +++ b/packages/react-native/ReactCommon/react/bridgeless/ReactInstance.cpp @@ -220,6 +220,9 @@ void ReactInstance::loadScript( if (hasLogger) { ReactMarker::logTaggedMarkerBridgeless( ReactMarker::RUN_JS_BUNDLE_STOP, scriptName.c_str()); + ReactMarker::logMarkerBridgeless( + ReactMarker::INIT_REACT_RUNTIME_STOP); + ReactMarker::logMarkerBridgeless(ReactMarker::APP_STARTUP_STOP); } if (auto strongBufferedRuntimeExecuter = weakBufferedRuntimeExecuter.lock()) { diff --git a/packages/react-native/ReactCommon/react/bridgeless/platform/ios/ReactCommon/RCTPerformanceLoggerUtils.mm b/packages/react-native/ReactCommon/react/bridgeless/platform/ios/ReactCommon/RCTPerformanceLoggerUtils.mm index 7a069100eeadb1..2d71e6f6b84dc3 100644 --- a/packages/react-native/ReactCommon/react/bridgeless/platform/ios/ReactCommon/RCTPerformanceLoggerUtils.mm +++ b/packages/react-native/ReactCommon/react/bridgeless/platform/ios/ReactCommon/RCTPerformanceLoggerUtils.mm @@ -23,6 +23,12 @@ static void mapReactMarkerToPerformanceLogger( case ReactMarker::APP_STARTUP_STOP: [performanceLogger markStopForTag:RCTPLAppStartup]; break; + case ReactMarker::INIT_REACT_RUNTIME_START: + [performanceLogger markStartForTag:RCTPLInitReactRuntime]; + break; + case ReactMarker::INIT_REACT_RUNTIME_STOP: + [performanceLogger markStopForTag:RCTPLInitReactRuntime]; + break; case ReactMarker::RUN_JS_BUNDLE_START: [performanceLogger markStartForTag:RCTPLScriptExecution]; break; diff --git a/packages/rn-tester/js/examples/Performance/PerformanceApiExample.js b/packages/rn-tester/js/examples/Performance/PerformanceApiExample.js index c9646efc2aa9d5..e7cfac597e1c49 100644 --- a/packages/rn-tester/js/examples/Performance/PerformanceApiExample.js +++ b/packages/rn-tester/js/examples/Performance/PerformanceApiExample.js @@ -73,6 +73,9 @@ function StartupTimingExample(): React.Node { {`startTime: ${ startUpTiming == null ? 'N/A' : startUpTiming.startTime } ms`} + {`initializeRuntimeStart: ${ + startUpTiming == null ? 'N/A' : startUpTiming.initializeRuntimeStart + } ms`} {`executeJavaScriptBundleEntryPointStart: ${ startUpTiming == null @@ -85,6 +88,9 @@ function StartupTimingExample(): React.Node { ? 'N/A' : startUpTiming.executeJavaScriptBundleEntryPointEnd } ms`} + {`initializeRuntimeEnd: ${ + startUpTiming == null ? 'N/A' : startUpTiming.initializeRuntimeEnd + } ms`} {`endTime: ${ startUpTiming == null ? 'N/A' : startUpTiming.endTime } ms`}