From e2bf843d8630fd7ab4f711495ec5d12faa9490cd Mon Sep 17 00:00:00 2001 From: Rafi Ciesielczuk Date: Fri, 22 Mar 2019 10:39:38 -0700 Subject: [PATCH] Introduce Module Setup Metric (#23859) Summary: The `RCTBridge` contains numerous definitions of notification names, which we can observe in order to get insights into the React Native performance. The Android implementation is a little different, such that you can listen for any of the [following](https://github.com/facebook/react-native/blob/master/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactMarkerConstants.java) marker constants, simply by including the following code: ```java ReactMarker.addListener(new ReactMarker.MarkerListener() { Override public void logMarker(ReactMarkerConstants name, Nullable String tag, int instanceKey) { Log.d("ReactNativeEvent", "name: "+ name.name() + " tag: " + tag); } }); ``` This will allow you to perform the necessary processing, calculations as required. --- This PR enables observing for the module setup event (`RCTDidSetupModuleNotification`) by including the respective module's name & setup time in milliseconds. [iOS] [Added] - Gain insights on the module setup times by observing `RCTDidSetupModuleNotification`. The `userInfo` dictionary will contain the module name and setup time in milliseconds. These values can be extracted via `RCTDidSetupModuleNotificationModuleNameKey ` and `RCTDidSetupModuleNotificationSetupTimeKey`. Pull Request resolved: https://github.com/facebook/react-native/pull/23859 Differential Revision: D14579066 Pulled By: PeteTheHeat fbshipit-source-id: 52645127c3fc6aa5bd73e3bd471fccd79cb05c14 --- React/Base/RCTBridge.h | 19 +++++++++++++++++++ React/Base/RCTBridge.m | 3 +++ React/Base/RCTPerformanceLogger.h | 1 + React/Base/RCTPerformanceLogger.m | 1 + React/CxxBridge/RCTCxxBridge.mm | 22 ++++++++++++++++++++-- 5 files changed, 44 insertions(+), 2 deletions(-) diff --git a/React/Base/RCTBridge.h b/React/Base/RCTBridge.h index a9150471d54..b8a394572d8 100644 --- a/React/Base/RCTBridge.h +++ b/React/Base/RCTBridge.h @@ -48,6 +48,25 @@ RCT_EXTERN NSString *const RCTJavaScriptDidFailToLoadNotification; */ RCT_EXTERN NSString *const RCTDidInitializeModuleNotification; +/** + * This notification fires each time a native module is setup after it is initialized. The + * `RCTDidSetupModuleNotificationModuleNameKey` key will contain a reference to the module name and + * `RCTDidSetupModuleNotificationSetupTimeKey` will contain the setup time in ms. + */ +RCT_EXTERN NSString *const RCTDidSetupModuleNotification; + +/** + * Key for the module name (NSString) in the + * RCTDidSetupModuleNotification userInfo dictionary. + */ +RCT_EXTERN NSString *const RCTDidSetupModuleNotificationModuleNameKey; + +/** + * Key for the setup time (NSNumber) in the + * RCTDidSetupModuleNotification userInfo dictionary. + */ +RCT_EXTERN NSString *const RCTDidSetupModuleNotificationSetupTimeKey; + /** * This notification fires just before the bridge starts processing a request to * reload. diff --git a/React/Base/RCTBridge.m b/React/Base/RCTBridge.m index 0ff789cf44c..ec16993a5cb 100644 --- a/React/Base/RCTBridge.m +++ b/React/Base/RCTBridge.m @@ -27,6 +27,9 @@ NSString *const RCTJavaScriptWillStartExecutingNotification = @"RCTJavaScriptWil NSString *const RCTJavaScriptDidLoadNotification = @"RCTJavaScriptDidLoadNotification"; NSString *const RCTJavaScriptDidFailToLoadNotification = @"RCTJavaScriptDidFailToLoadNotification"; NSString *const RCTDidInitializeModuleNotification = @"RCTDidInitializeModuleNotification"; +NSString *const RCTDidSetupModuleNotification = @"RCTDidSetupModuleNotification"; +NSString *const RCTDidSetupModuleNotificationModuleNameKey = @"moduleName"; +NSString *const RCTDidSetupModuleNotificationSetupTimeKey = @"setupTime"; NSString *const RCTBridgeWillReloadNotification = @"RCTBridgeWillReloadNotification"; NSString *const RCTBridgeWillDownloadScriptNotification = @"RCTBridgeWillDownloadScriptNotification"; NSString *const RCTBridgeDidDownloadScriptNotification = @"RCTBridgeDidDownloadScriptNotification"; diff --git a/React/Base/RCTPerformanceLogger.h b/React/Base/RCTPerformanceLogger.h index f1a615f49e4..5e540dc8d4d 100644 --- a/React/Base/RCTPerformanceLogger.h +++ b/React/Base/RCTPerformanceLogger.h @@ -20,6 +20,7 @@ typedef NS_ENUM(NSUInteger, RCTPLTag) { RCTPLNativeModuleMainThread, RCTPLNativeModulePrepareConfig, RCTPLNativeModuleMainThreadUsesCount, + RCTPLNativeModuleSetup, RCTPLJSCWrapperOpenLibrary, RCTPLBridgeStartup, RCTPLTTI, diff --git a/React/Base/RCTPerformanceLogger.m b/React/Base/RCTPerformanceLogger.m index af7cc7118c8..1d728f34a3f 100644 --- a/React/Base/RCTPerformanceLogger.m +++ b/React/Base/RCTPerformanceLogger.m @@ -41,6 +41,7 @@ @"NativeModulePrepareConfig", @"NativeModuleInjectConfig", @"NativeModuleMainThreadUsesCount", + @"NativeModuleSetup", @"JSCWrapperOpenLibrary", @"JSCExecutorSetup", @"BridgeStartup", diff --git a/React/CxxBridge/RCTCxxBridge.mm b/React/CxxBridge/RCTCxxBridge.mm index d3ac53820c0..6f0aeed7cb6 100644 --- a/React/CxxBridge/RCTCxxBridge.mm +++ b/React/CxxBridge/RCTCxxBridge.mm @@ -99,6 +99,19 @@ static bool isRAMBundle(NSData *script) { return parseTypeFromHeader(header) == ScriptTag::RAMBundle; } +static void notifyAboutModuleSetup(RCTPerformanceLogger *performanceLogger, const char *tag) { + NSString *moduleName = [[NSString alloc] initWithUTF8String:tag]; + if (moduleName) { + int64_t setupTime = [performanceLogger durationForTag:RCTPLNativeModuleSetup]; + [[NSNotificationCenter defaultCenter] postNotificationName:RCTDidSetupModuleNotification + object:nil + userInfo:@{ + RCTDidSetupModuleNotificationModuleNameKey: moduleName, + RCTDidSetupModuleNotificationSetupTimeKey: @(setupTime) + }]; + } +} + static void registerPerformanceLoggerHooks(RCTPerformanceLogger *performanceLogger) { __weak RCTPerformanceLogger *weakPerformanceLogger = performanceLogger; ReactMarker::logTaggedMarker = [weakPerformanceLogger](const ReactMarker::ReactMarkerId markerId, const char *__unused tag) { @@ -116,11 +129,16 @@ static void registerPerformanceLoggerHooks(RCTPerformanceLogger *performanceLogg [weakPerformanceLogger appendStopForTag:RCTPLRAMNativeRequires]; [weakPerformanceLogger addValue:1 forTag:RCTPLRAMNativeRequiresCount]; break; + case ReactMarker::NATIVE_MODULE_SETUP_START: + [weakPerformanceLogger markStartForTag:RCTPLNativeModuleSetup]; + break; + case ReactMarker::NATIVE_MODULE_SETUP_STOP: + [weakPerformanceLogger markStopForTag:RCTPLNativeModuleSetup]; + notifyAboutModuleSetup(weakPerformanceLogger, tag); + break; case ReactMarker::CREATE_REACT_CONTEXT_STOP: case ReactMarker::JS_BUNDLE_STRING_CONVERT_START: case ReactMarker::JS_BUNDLE_STRING_CONVERT_STOP: - case ReactMarker::NATIVE_MODULE_SETUP_START: - case ReactMarker::NATIVE_MODULE_SETUP_STOP: case ReactMarker::REGISTER_JS_SEGMENT_START: case ReactMarker::REGISTER_JS_SEGMENT_STOP: // These are not used on iOS.