diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m index 98d0615db4..4ea36012a2 100644 --- a/React/Base/RCTBatchedBridge.m +++ b/React/Base/RCTBatchedBridge.m @@ -97,7 +97,7 @@ RCT_EXTERN NSArray *RCTGetModuleClasses(void); dispatch_group_enter(initModulesAndLoadSource); __weak RCTBatchedBridge *weakSelf = self; __block NSData *sourceCode; - [self loadSource:^(NSError *error, NSData *source) { + [self loadSource:^(NSError *error, NSData *source, int64_t sourceLength) { if (error) { dispatch_async(dispatch_get_main_queue(), ^{ [weakSelf stopLoadingWithError:error]; @@ -111,6 +111,7 @@ RCT_EXTERN NSArray *RCTGetModuleClasses(void); // Synchronously initialize all native modules that cannot be loaded lazily [self initModulesWithDispatchGroup:initModulesAndLoadSource]; + RCTPerformanceLogger *performanceLogger = self->_performanceLogger; __block NSString *config; dispatch_group_enter(initModulesAndLoadSource); dispatch_async(bridgeQueue, ^{ @@ -118,17 +119,17 @@ RCT_EXTERN NSArray *RCTGetModuleClasses(void); // Asynchronously initialize the JS executor dispatch_group_async(setupJSExecutorAndModuleConfig, bridgeQueue, ^{ - RCTPerformanceLoggerStart(RCTPLJSCExecutorSetup); + [performanceLogger markStartForTag:RCTPLJSCExecutorSetup]; [weakSelf setUpExecutor]; - RCTPerformanceLoggerEnd(RCTPLJSCExecutorSetup); + [performanceLogger markStopForTag:RCTPLJSCExecutorSetup]; }); // Asynchronously gather the module config dispatch_group_async(setupJSExecutorAndModuleConfig, bridgeQueue, ^{ if (weakSelf.valid) { - RCTPerformanceLoggerStart(RCTPLNativeModulePrepareConfig); + [performanceLogger markStartForTag:RCTPLNativeModulePrepareConfig]; config = [weakSelf moduleConfig]; - RCTPerformanceLoggerEnd(RCTPLNativeModulePrepareConfig); + [performanceLogger markStopForTag:RCTPLNativeModulePrepareConfig]; } }); @@ -136,9 +137,9 @@ RCT_EXTERN NSArray *RCTGetModuleClasses(void); // We're not waiting for this to complete to leave dispatch group, since // injectJSONConfiguration and executeSourceCode will schedule operations // on the same queue anyway. - RCTPerformanceLoggerStart(RCTPLNativeModuleInjectConfig); + [performanceLogger markStartForTag:RCTPLNativeModuleInjectConfig]; [weakSelf injectJSONConfiguration:config onComplete:^(NSError *error) { - RCTPerformanceLoggerEnd(RCTPLNativeModuleInjectConfig); + [performanceLogger markStopForTag:RCTPLNativeModuleInjectConfig]; if (error) { dispatch_async(dispatch_get_main_queue(), ^{ [weakSelf stopLoadingWithError:error]; @@ -159,18 +160,19 @@ RCT_EXTERN NSArray *RCTGetModuleClasses(void); - (void)loadSource:(RCTSourceLoadBlock)_onSourceLoad { - RCTPerformanceLoggerStart(RCTPLScriptDownload); + [_performanceLogger markStartForTag:RCTPLScriptDownload]; - RCTSourceLoadBlock onSourceLoad = ^(NSError *error, NSData *source) { - RCTPerformanceLoggerEnd(RCTPLScriptDownload); - - _onSourceLoad(error, source); + RCTPerformanceLogger *performanceLogger = _performanceLogger; + RCTSourceLoadBlock onSourceLoad = ^(NSError *error, NSData *source, int64_t sourceLength) { + [performanceLogger markStopForTag:RCTPLScriptDownload]; + [performanceLogger setValue:sourceLength forTag:RCTPLBundleSize]; + _onSourceLoad(error, source, sourceLength); }; if ([self.delegate respondsToSelector:@selector(loadSourceForBridge:withBlock:)]) { [self.delegate loadSourceForBridge:_parentBridge withBlock:onSourceLoad]; } else if (self.bundleURL) { - [RCTJavaScriptLoader loadBundleAtURL:self.bundleURL onComplete:^(NSError *error, NSData *source) { + [RCTJavaScriptLoader loadBundleAtURL:self.bundleURL onComplete:^(NSError *error, NSData *source, int64_t sourceLength) { if (error && [self.delegate respondsToSelector:@selector(fallbackSourceURLForBridge:)]) { NSURL *fallbackURL = [self.delegate fallbackSourceURLForBridge:_parentBridge]; if (fallbackURL && ![fallbackURL isEqual:self.bundleURL]) { @@ -180,7 +182,7 @@ RCT_EXTERN NSArray *RCTGetModuleClasses(void); return; } } - onSourceLoad(error, source); + onSourceLoad(error, source, sourceLength); }]; } else { // Allow testing without a script @@ -190,7 +192,7 @@ RCT_EXTERN NSArray *RCTGetModuleClasses(void); postNotificationName:RCTJavaScriptDidLoadNotification object:_parentBridge userInfo:@{@"bridge": self}]; }); - onSourceLoad(nil, nil); + onSourceLoad(nil, nil, 0); } } @@ -235,7 +237,7 @@ RCT_EXTERN NSArray *RCTGetModuleClasses(void); - (void)initModulesWithDispatchGroup:(dispatch_group_t)dispatchGroup { - RCTPerformanceLoggerStart(RCTPLNativeModuleInit); + [_performanceLogger markStartForTag:RCTPLNativeModuleInit]; NSArray> *extraModules = nil; if (self.delegate) { @@ -382,7 +384,7 @@ RCT_EXTERN NSArray *RCTGetModuleClasses(void); _moduleSetupComplete = YES; // Set up modules that require main thread init or constants export - RCTPerformanceLoggerSet(RCTPLNativeModuleMainThread, 0); + [_performanceLogger setValue:0 forTag:RCTPLNativeModuleMainThread]; NSUInteger modulesOnMainQueueCount = 0; for (RCTModuleData *moduleData in _moduleDataByID) { __weak RCTBatchedBridge *weakSelf = self; @@ -393,19 +395,22 @@ RCT_EXTERN NSArray *RCTGetModuleClasses(void); // modules on the main thread in parallel with loading the JS code, so // they will already be available before they are ever required. dispatch_group_async(dispatchGroup, dispatch_get_main_queue(), ^{ - if (weakSelf.valid) { - RCTPerformanceLoggerAppendStart(RCTPLNativeModuleMainThread); - (void)[moduleData instance]; - [moduleData gatherConstants]; - RCTPerformanceLoggerAppendEnd(RCTPLNativeModuleMainThread); + RCTBatchedBridge *strongSelf = weakSelf; + if (!strongSelf.valid) { + return; } + + [strongSelf->_performanceLogger appendStartForTag:RCTPLNativeModuleMainThread]; + (void)[moduleData instance]; + [moduleData gatherConstants]; + [strongSelf->_performanceLogger appendStopForTag:RCTPLNativeModuleMainThread]; }); modulesOnMainQueueCount++; } } - RCTPerformanceLoggerEnd(RCTPLNativeModuleInit); - RCTPerformanceLoggerSet(RCTPLNativeModuleMainThreadUsesCount, modulesOnMainQueueCount); + [_performanceLogger markStopForTag:RCTPLNativeModuleInit]; + [_performanceLogger setValue:modulesOnMainQueueCount forTag:RCTPLNativeModuleMainThreadUsesCount]; } - (void)setUpExecutor @@ -497,7 +502,7 @@ RCT_EXTERN NSArray *RCTGetModuleClasses(void); - (void)didFinishLoading { - RCTPerformanceLoggerEnd(RCTPLBridgeStartup); + [_performanceLogger markStopForTag:RCTPLBridgeStartup]; _loading = NO; [_javaScriptExecutor executeBlockOnJavaScriptQueue:^{ for (dispatch_block_t call in _pendingCalls) { diff --git a/React/Base/RCTBridge+Private.h b/React/Base/RCTBridge+Private.h index fd0dd9a38f..08dd70557b 100644 --- a/React/Base/RCTBridge+Private.h +++ b/React/Base/RCTBridge+Private.h @@ -10,8 +10,13 @@ #import "RCTBridge.h" @class RCTModuleData; +@class RCTPerformanceLogger; @interface RCTBridge () +{ +@public + RCTPerformanceLogger *_performanceLogger; +} // Used for the profiler flow events between JS and native @property (nonatomic, assign) int64_t flowID; diff --git a/React/Base/RCTBridge.h b/React/Base/RCTBridge.h index 18cf73876e..956244ca67 100644 --- a/React/Base/RCTBridge.h +++ b/React/Base/RCTBridge.h @@ -18,6 +18,7 @@ @class RCTBridge; @class RCTEventDispatcher; +@class RCTPerformanceLogger; /** * This notification triggers a reload of all bridges currently running. @@ -160,6 +161,11 @@ RCT_EXTERN NSString *RCTBridgeModuleNameForClass(Class bridgeModuleClass); */ @property (nonatomic, readonly, getter=isValid) BOOL valid; +/** + * Link to the Performance Logger that logs React Native perf events. + */ +@property (nonatomic, readonly, strong) RCTPerformanceLogger *performanceLogger; + /** * Reload the bundle and reset executor & modules. Safe to call from any thread. */ diff --git a/React/Base/RCTBridge.m b/React/Base/RCTBridge.m index 5721bc0f06..775ddff9b6 100644 --- a/React/Base/RCTBridge.m +++ b/React/Base/RCTBridge.m @@ -110,26 +110,36 @@ static RCTBridge *RCTCurrentBridgeInstance = nil; - (instancetype)initWithDelegate:(id)delegate launchOptions:(NSDictionary *)launchOptions { - if ((self = [super init])) { - RCTPerformanceLoggerStart(RCTPLBridgeStartup); - RCTPerformanceLoggerStart(RCTPLTTI); - - _delegate = delegate; - _launchOptions = [launchOptions copy]; - [self setUp]; - RCTExecuteOnMainQueue(^{ [self bindKeys]; }); - } - return self; + return [self initWithDelegate:delegate + bundleURL:nil + moduleProvider:nil + launchOptions:launchOptions]; } - (instancetype)initWithBundleURL:(NSURL *)bundleURL moduleProvider:(RCTBridgeModuleProviderBlock)block launchOptions:(NSDictionary *)launchOptions { - if ((self = [super init])) { - RCTPerformanceLoggerStart(RCTPLBridgeStartup); - RCTPerformanceLoggerStart(RCTPLTTI); + return [self initWithDelegate:nil + bundleURL:bundleURL + moduleProvider:block + launchOptions:launchOptions]; +} +/** + * Private designated initializer + */ +- (instancetype)initWithDelegate:(id)delegate + bundleURL:(NSURL *)bundleURL + moduleProvider:(RCTBridgeModuleProviderBlock)block + launchOptions:(NSDictionary *)launchOptions +{ + if ((self = [super init])) { + _performanceLogger = [RCTPerformanceLogger new]; + [_performanceLogger markStartForTag:RCTPLBridgeStartup]; + [_performanceLogger markStartForTag:RCTPLTTI]; + + _delegate = delegate; _bundleURL = bundleURL; _moduleProvider = block; _launchOptions = [launchOptions copy]; diff --git a/React/Base/RCTBridgeDelegate.h b/React/Base/RCTBridgeDelegate.h index 8d85f78b7a..baa3f5db1c 100644 --- a/React/Base/RCTBridgeDelegate.h +++ b/React/Base/RCTBridgeDelegate.h @@ -7,7 +7,7 @@ * of patent rights can be found in the PATENTS file in the same directory. */ -typedef void (^RCTSourceLoadBlock)(NSError *error, NSData *source); +typedef void (^RCTSourceLoadBlock)(NSError *error, NSData *source, int64_t sourceLength); @class RCTBridge; diff --git a/React/Base/RCTJavaScriptLoader.m b/React/Base/RCTJavaScriptLoader.m index f677db64e2..8b6b0b750e 100755 --- a/React/Base/RCTJavaScriptLoader.m +++ b/React/Base/RCTJavaScriptLoader.m @@ -35,7 +35,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) NSError *error = [NSError errorWithDomain:@"JavaScriptLoader" code:1 userInfo:@{ NSLocalizedDescriptionKey: errorDescription }]; - onComplete(error, nil); + onComplete(error, nil, 0); return; } @@ -51,14 +51,14 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) // modules into JSC as they're required. FILE *bundle = fopen(scriptURL.path.UTF8String, "r"); if (!bundle) { - onComplete(RCTErrorWithMessage([NSString stringWithFormat:@"Error opening bundle %@", scriptURL.path]), source); + onComplete(RCTErrorWithMessage([NSString stringWithFormat:@"Error opening bundle %@", scriptURL.path]), source, 0); return; } uint32_t magicNumber; if (fread(&magicNumber, sizeof(magicNumber), 1, bundle) != 1) { fclose(bundle); - onComplete(RCTErrorWithMessage(@"Error reading bundle"), source); + onComplete(RCTErrorWithMessage(@"Error reading bundle"), source, 0); return; } @@ -81,9 +81,8 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) sourceLength = source.length; } - RCTPerformanceLoggerSet(RCTPLBundleSize, sourceLength); fclose(bundle); - onComplete(error, source); + onComplete(error, source, sourceLength); }); return; } @@ -105,7 +104,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) code:error.code userInfo:userInfo]; } - onComplete(error, nil); + onComplete(error, nil, 0); return; } @@ -143,11 +142,10 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) code:((NSHTTPURLResponse *)response).statusCode userInfo:userInfo]; - onComplete(error, nil); + onComplete(error, nil, 0); return; } - RCTPerformanceLoggerSet(RCTPLBundleSize, data.length); - onComplete(nil, data); + onComplete(nil, data, data.length); }]; [task resume]; diff --git a/React/Base/RCTPerformanceLogger.h b/React/Base/RCTPerformanceLogger.h index 3cfd62b0f6..9477a0ec67 100644 --- a/React/Base/RCTPerformanceLogger.h +++ b/React/Base/RCTPerformanceLogger.h @@ -9,8 +9,6 @@ #import -#import "RCTDefines.h" - typedef NS_ENUM(NSUInteger, RCTPLTag) { RCTPLScriptDownload = 0, RCTPLScriptExecution, @@ -25,7 +23,6 @@ typedef NS_ENUM(NSUInteger, RCTPLTag) { RCTPLNativeModuleInjectConfig, RCTPLNativeModuleMainThreadUsesCount, RCTPLJSCWrapperOpenLibrary, - RCTPLJSCWrapperLoadFunctions, RCTPLJSCExecutorSetup, RCTPLBridgeStartup, RCTPLTTI, @@ -33,44 +30,74 @@ typedef NS_ENUM(NSUInteger, RCTPLTag) { RCTPLSize }; +@interface RCTPerformanceLogger : NSObject + /** * Starts measuring a metric with the given tag. * Overrides previous value if the measurement has been already started. * If RCTProfile is enabled it also begins appropriate async event. + * All work is scheduled on the background queue so this doesn't block current thread. */ -RCT_EXTERN void RCTPerformanceLoggerStart(RCTPLTag tag); +- (void)markStartForTag:(RCTPLTag)tag; /** * Stops measuring a metric with given tag. * Checks if RCTPerformanceLoggerStart() has been called before * and doesn't do anything and log a message if it hasn't. * If RCTProfile is enabled it also ends appropriate async event. + * All work is scheduled on the background queue so this doesn't block current thread. */ -RCT_EXTERN void RCTPerformanceLoggerEnd(RCTPLTag tag); +- (void)markStopForTag:(RCTPLTag)tag; /** * Sets given value for a metric with given tag. + * All work is scheduled on the background queue so this doesn't block current thread. */ -RCT_EXTERN void RCTPerformanceLoggerSet(RCTPLTag tag, int64_t value); +- (void)setValue:(int64_t)value forTag:(RCTPLTag)tag; /** * Adds given value to the current value for a metric with given tag. + * All work is scheduled on the background queue so this doesn't block current thread. */ -RCT_EXTERN void RCTPerformanceLoggerAdd(RCTPLTag tag, int64_t value); +- (void)addValue:(int64_t)value forTag:(RCTPLTag)tag; /** * Starts an additional measurement for a metric with given tag. * It doesn't override previous measurement, instead it'll append a new value * to the old one. + * All work is scheduled on the background queue so this doesn't block current thread. */ -RCT_EXTERN void RCTPerformanceLoggerAppendStart(RCTPLTag tag); +- (void)appendStartForTag:(RCTPLTag)tag; /** * Stops measurement and appends the result to the metric with given tag. * Checks if RCTPerformanceLoggerAppendStart() has been called before * and doesn't do anything and log a message if it hasn't. + * All work is scheduled on the background queue so this doesn't block current thread. */ -RCT_EXTERN void RCTPerformanceLoggerAppendEnd(RCTPLTag tag); +- (void)appendStopForTag:(RCTPLTag)tag; -RCT_EXTERN NSArray *RCTPerformanceLoggerOutput(void); -RCT_EXTERN NSArray *RCTPerformanceLoggerLabels(void); +/** + * Returns an array with values for all tags. + * Use RCTPLTag to go over the array, there's a pair of values + * for each tag: start and stop (with indexes 2 * tag and 2 * tag + 1). + */ +- (NSArray *)valuesForTags; + +/** + * Returns a duration (stop_time - start_time) for given RCTPLTag. + */ +- (int64_t)durationForTag:(RCTPLTag)tag; + +/** + * Returns a value for given RCTPLTag. + */ +- (int64_t)valueForTag:(RCTPLTag)tag; + +/** + * Returns an array with values for all tags. + * Use RCTPLTag to go over the array. + */ +- (NSArray *)labelsForTags; + +@end diff --git a/React/Base/RCTPerformanceLogger.m b/React/Base/RCTPerformanceLogger.m index 68e38f434f..5046990214 100644 --- a/React/Base/RCTPerformanceLogger.m +++ b/React/Base/RCTPerformanceLogger.m @@ -14,77 +14,22 @@ #import "RCTLog.h" #import "RCTProfile.h" -static int64_t RCTPLData[RCTPLSize][2] = {}; -static NSUInteger RCTPLCookies[RCTPLSize] = {}; - -void RCTPerformanceLoggerStart(RCTPLTag tag) +@interface RCTPerformanceLogger () { - if (RCTProfileIsProfiling()) { - NSString *label = RCTPerformanceLoggerLabels()[tag]; - RCTPLCookies[tag] = RCTProfileBeginAsyncEvent(RCTProfileTagAlways, label, nil); - } - - RCTPLData[tag][0] = CACurrentMediaTime() * 1000; - RCTPLData[tag][1] = 0; + int64_t _data[RCTPLSize][2]; + NSUInteger _cookies[RCTPLSize]; } -void RCTPerformanceLoggerEnd(RCTPLTag tag) -{ - if (RCTPLData[tag][0] != 0 && RCTPLData[tag][1] == 0) { - RCTPLData[tag][1] = CACurrentMediaTime() * 1000; +@property (nonatomic, copy) NSArray *labelsForTags; - if (RCTProfileIsProfiling()) { - NSString *label = RCTPerformanceLoggerLabels()[tag]; - RCTProfileEndAsyncEvent(RCTProfileTagAlways, @"native", RCTPLCookies[tag], label, @"RCTPerformanceLogger", nil); - } - } else { - RCTLogInfo(@"Unbalanced calls start/end for tag %li", (unsigned long)tag); - } -} +@end -void RCTPerformanceLoggerSet(RCTPLTag tag, int64_t value) -{ - RCTPLData[tag][0] = 0; - RCTPLData[tag][1] = value; -} +@implementation RCTPerformanceLogger -void RCTPerformanceLoggerAdd(RCTPLTag tag, int64_t value) +- (instancetype)init { - RCTPLData[tag][0] = 0; - RCTPLData[tag][1] += value; -} - -void RCTPerformanceLoggerAppendStart(RCTPLTag tag) -{ - RCTPLData[tag][0] = CACurrentMediaTime() * 1000; -} - -void RCTPerformanceLoggerAppendEnd(RCTPLTag tag) -{ - if (RCTPLData[tag][0] != 0) { - RCTPLData[tag][1] += CACurrentMediaTime() * 1000 - RCTPLData[tag][0]; - RCTPLData[tag][0] = 0; - } else { - RCTLogInfo(@"Unbalanced calls start/end for tag %li", (unsigned long)tag); - } -} - -NSArray *RCTPerformanceLoggerOutput(void) -{ - NSMutableArray *result = [NSMutableArray array]; - for (NSUInteger index = 0; index < RCTPLSize; index++) { - [result addObject:@(RCTPLData[index][0])]; - [result addObject:@(RCTPLData[index][1])]; - } - return result; -} - -NSArray *RCTPerformanceLoggerLabels(void) -{ - static NSArray *labels; - static dispatch_once_t token; - dispatch_once(&token, ^{ - labels = @[ + if (self = [super init]) { + _labelsForTags = @[ @"ScriptDownload", @"ScriptExecution", @"RAMBundleLoad", @@ -98,56 +43,84 @@ NSArray *RCTPerformanceLoggerLabels(void) @"NativeModuleInjectConfig", @"NativeModuleMainThreadUsesCount", @"JSCWrapperOpenLibrary", - @"JSCWrapperLoadFunctions", @"JSCExecutorSetup", @"BridgeStartup", @"RootViewTTI", @"BundleSize", ]; - }); - return labels; + } + return self; } -@interface RCTPerformanceLogger : NSObject - -@end - -@implementation RCTPerformanceLogger - -RCT_EXPORT_MODULE() - -@synthesize bridge = _bridge; - -- (instancetype)init +- (void)markStartForTag:(RCTPLTag)tag { - // We're only overriding this to ensure the module gets created at startup - // TODO (t11106126): Remove once we have more declarative control over module setup. - return [super init]; + if (RCTProfileIsProfiling()) { + NSString *label = _labelsForTags[tag]; + _cookies[tag] = RCTProfileBeginAsyncEvent(RCTProfileTagAlways, label, nil); + } + _data[tag][0] = CACurrentMediaTime() * 1000; + _data[tag][1] = 0; } -- (void)setBridge:(RCTBridge *)bridge -{ - _bridge = bridge; - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(sendTimespans) - name:RCTContentDidAppearNotification - object:nil]; +- (void)markStopForTag:(RCTPLTag)tag +{ + if (RCTProfileIsProfiling()) { + NSString *label =_labelsForTags[tag]; + RCTProfileEndAsyncEvent(RCTProfileTagAlways, @"native", _cookies[tag], label, @"RCTPerformanceLogger", nil); + } + if (_data[tag][0] != 0 && _data[tag][1] == 0) { + _data[tag][1] = CACurrentMediaTime() * 1000; + } else { + RCTLogInfo(@"Unbalanced calls start/end for tag %li", (unsigned long)tag); + } } -- (void)dealloc +- (void)setValue:(int64_t)value forTag:(RCTPLTag)tag { - [[NSNotificationCenter defaultCenter] removeObserver:self]; + _data[tag][0] = 0; + _data[tag][1] = value; } -- (void)sendTimespans +- (void)addValue:(int64_t)value forTag:(RCTPLTag)tag { - [[NSNotificationCenter defaultCenter] removeObserver:self]; + _data[tag][0] = 0; + _data[tag][1] += value; +} - [_bridge enqueueJSCall:@"PerformanceLogger.addTimespans" args:@[ - RCTPerformanceLoggerOutput(), - RCTPerformanceLoggerLabels(), - ]]; +- (void)appendStartForTag:(RCTPLTag)tag +{ + _data[tag][0] = CACurrentMediaTime() * 1000; +} + +- (void)appendStopForTag:(RCTPLTag)tag +{ + if (_data[tag][0] != 0) { + _data[tag][1] += CACurrentMediaTime() * 1000 - _data[tag][0]; + _data[tag][0] = 0; + } else { + RCTLogInfo(@"Unbalanced calls start/end for tag %li", (unsigned long)tag); + } +} + +- (NSArray *)valuesForTags +{ + NSMutableArray *result = [NSMutableArray array]; + for (NSUInteger index = 0; index < RCTPLSize; index++) { + [result addObject:@(_data[index][0])]; + [result addObject:@(_data[index][1])]; + } + return result; +} + +- (int64_t)durationForTag:(RCTPLTag)tag +{ + return _data[tag][1] - _data[tag][0]; +} + +- (int64_t)valueForTag:(RCTPLTag)tag; +{ + return _data[tag][1]; } @end diff --git a/React/Base/RCTRootView.m b/React/Base/RCTRootView.m index 78896f5fe4..d335aac834 100644 --- a/React/Base/RCTRootView.m +++ b/React/Base/RCTRootView.m @@ -340,7 +340,7 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder:(nonnull NSCoder *)aDecoder) - (void)insertReactSubview:(UIView *)subview atIndex:(NSInteger)atIndex { [super insertReactSubview:subview atIndex:atIndex]; - RCTPerformanceLoggerEnd(RCTPLTTI); + [_bridge->_performanceLogger markStopForTag:RCTPLTTI]; dispatch_async(dispatch_get_main_queue(), ^{ if (!_contentHasAppeared) { _contentHasAppeared = YES; diff --git a/React/Executors/RCTJSCExecutor.mm b/React/Executors/RCTJSCExecutor.mm index 4da25b0303..506b5119b8 100644 --- a/React/Executors/RCTJSCExecutor.mm +++ b/React/Executors/RCTJSCExecutor.mm @@ -136,6 +136,8 @@ RCT_NOT_IMPLEMENTED(-(instancetype)init) RCTJSCWrapper *_jscWrapper; BOOL _useCustomJSCLibrary; + + RCTPerformanceLogger *_performanceLogger; } @synthesize valid = _valid; @@ -263,6 +265,12 @@ static void RCTInstallJSCProfiler(RCTBridge *bridge, JSContextRef context) } } +- (void)setBridge:(RCTBridge *)bridge +{ + _bridge = bridge; + _performanceLogger = [bridge performanceLogger]; +} + - (instancetype)init { return [self initWithUseCustomJSCLibrary:NO]; @@ -328,7 +336,9 @@ static void RCTInstallJSCProfiler(RCTBridge *bridge, JSContextRef context) return; } + [strongSelf->_performanceLogger markStartForTag:RCTPLJSCWrapperOpenLibrary]; strongSelf->_jscWrapper = RCTJSCWrapperCreate(strongSelf->_useCustomJSCLibrary); + [strongSelf->_performanceLogger markStopForTag:RCTPLJSCWrapperOpenLibrary]; }]; @@ -660,14 +670,13 @@ static void RCTInstallJSCProfiler(RCTBridge *bridge, JSContextRef context) } __weak RCTJSCExecutor *weakSelf = self; - [self executeBlockOnJavaScriptQueue:RCTProfileBlock((^{ RCTJSCExecutor *strongSelf = weakSelf; if (!strongSelf || !strongSelf.isValid) { return; } - RCTPerformanceLoggerStart(RCTPLScriptExecution); + [strongSelf->_performanceLogger markStartForTag:RCTPLScriptExecution]; JSValueRef jsError = NULL; RCTJSCWrapper *jscWrapper = strongSelf->_jscWrapper; @@ -676,7 +685,8 @@ static void RCTInstallJSCProfiler(RCTBridge *bridge, JSContextRef context) JSValueRef result = jscWrapper->JSEvaluateScript(strongSelf->_context.ctx, execJSString, NULL, bundleURL, 0, &jsError); jscWrapper->JSStringRelease(bundleURL); jscWrapper->JSStringRelease(execJSString); - RCTPerformanceLoggerEnd(RCTPLScriptExecution); + + [strongSelf->_performanceLogger markStopForTag:RCTPLScriptExecution]; if (onComplete) { NSError *error; @@ -783,9 +793,9 @@ static void executeRandomAccessModule(RCTJSCExecutor *executor, uint32_t moduleI - (void)registerNativeRequire { - RCTPerformanceLoggerSet(RCTPLRAMNativeRequires, 0); - RCTPerformanceLoggerSet(RCTPLRAMNativeRequiresCount, 0); - RCTPerformanceLoggerSet(RCTPLRAMNativeRequiresSize, 0); + [_performanceLogger setValue:0 forTag:RCTPLRAMNativeRequires]; + [_performanceLogger setValue:0 forTag:RCTPLRAMNativeRequiresCount]; + [_performanceLogger setValue:0 forTag:RCTPLRAMNativeRequiresSize]; __weak RCTJSCExecutor *weakSelf = self; [self addSynchronousHookWithName:@"nativeRequire" usingBlock:^(NSNumber *moduleID) { @@ -794,8 +804,8 @@ static void executeRandomAccessModule(RCTJSCExecutor *executor, uint32_t moduleI return; } - RCTPerformanceLoggerAdd(RCTPLRAMNativeRequiresCount, 1); - RCTPerformanceLoggerAppendStart(RCTPLRAMNativeRequires); + [strongSelf->_performanceLogger addValue:1 forTag:RCTPLRAMNativeRequiresCount]; + [strongSelf->_performanceLogger appendStartForTag:RCTPLRAMNativeRequires]; RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, [@"nativeRequire_" stringByAppendingFormat:@"%@", moduleID], nil); @@ -810,12 +820,12 @@ static void executeRandomAccessModule(RCTJSCExecutor *executor, uint32_t moduleI return; } - RCTPerformanceLoggerAdd(RCTPLRAMNativeRequiresSize, size); + [strongSelf->_performanceLogger addValue:size forTag:RCTPLRAMNativeRequiresSize]; executeRandomAccessModule(strongSelf, ID, NSSwapLittleIntToHost(moduleData->offset), size); } RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"js_call", nil); - RCTPerformanceLoggerAppendEnd(RCTPLRAMNativeRequires); + [strongSelf->_performanceLogger appendStopForTag:RCTPLRAMNativeRequires]; }]; } @@ -858,7 +868,7 @@ static RandomAccessBundleStartupCode readRAMBundle(file_ptr bundle, RandomAccess - (NSData *)loadRAMBundle:(NSURL *)sourceURL error:(NSError **)error { - RCTPerformanceLoggerStart(RCTPLRAMBundleLoad); + [_performanceLogger markStartForTag:RCTPLRAMBundleLoad]; file_ptr bundle(fopen(sourceURL.path.UTF8String, "r"), fclose); if (!bundle) { if (error) { @@ -878,8 +888,8 @@ static RandomAccessBundleStartupCode readRAMBundle(file_ptr bundle, RandomAccess return nil; } - RCTPerformanceLoggerEnd(RCTPLRAMBundleLoad); - RCTPerformanceLoggerSet(RCTPLRAMStartupCodeSize, startupCode.size); + [_performanceLogger markStopForTag:RCTPLRAMBundleLoad]; + [_performanceLogger setValue:startupCode.size forTag:RCTPLRAMStartupCodeSize]; return [NSData dataWithBytesNoCopy:startupCode.code.release() length:startupCode.size freeWhenDone:YES]; } diff --git a/React/Executors/RCTJSCWrapper.mm b/React/Executors/RCTJSCWrapper.mm index eb7696f09c..222ebfc661 100644 --- a/React/Executors/RCTJSCWrapper.mm +++ b/React/Executors/RCTJSCWrapper.mm @@ -13,7 +13,6 @@ #import #import "RCTLog.h" -#import "RCTPerformanceLogger.h" #include @@ -26,9 +25,7 @@ static void *RCTCustomLibraryHandler(void) ofType:nil inDirectory:@"Frameworks/JavaScriptCore.framework"] UTF8String]; if (path) { - RCTPerformanceLoggerStart(RCTPLJSCWrapperOpenLibrary); handler = dlopen(path, RTLD_LAZY); - RCTPerformanceLoggerEnd(RCTPLJSCWrapperOpenLibrary); if (!handler) { RCTLogWarn(@"Can't load custom JSC library: %s", dlerror()); } @@ -69,7 +66,6 @@ static void RCTSetUpCustomLibraryPointers(RCTJSCWrapper *wrapper) return; } - RCTPerformanceLoggerStart(RCTPLJSCWrapperLoadFunctions); wrapper->JSValueToStringCopy = (JSValueToStringCopyFuncType)dlsym(libraryHandle, "JSValueToStringCopy"); wrapper->JSStringCreateWithCFString = (JSStringCreateWithCFStringFuncType)dlsym(libraryHandle, "JSStringCreateWithCFString"); wrapper->JSStringCopyCFString = (JSStringCopyCFStringFuncType)dlsym(libraryHandle, "JSStringCopyCFString"); @@ -90,7 +86,6 @@ static void RCTSetUpCustomLibraryPointers(RCTJSCWrapper *wrapper) wrapper->JSContext = (__bridge Class)dlsym(libraryHandle, "OBJC_CLASS_$_JSContext"); wrapper->JSValue = (__bridge Class)dlsym(libraryHandle, "OBJC_CLASS_$_JSValue"); wrapper->configureJSContextForIOS = (configureJSContextForIOSFuncType)dlsym(libraryHandle, "configureJSContextForIOS"); - RCTPerformanceLoggerEnd(RCTPLJSCWrapperLoadFunctions); } RCTJSCWrapper *RCTJSCWrapperCreate(BOOL useCustomJSC) diff --git a/React/Profiler/RCTPerfMonitor.m b/React/Profiler/RCTPerfMonitor.m index 947722534f..5c0ac16554 100644 --- a/React/Profiler/RCTPerfMonitor.m +++ b/React/Profiler/RCTPerfMonitor.m @@ -510,8 +510,9 @@ RCT_EXPORT_MODULE() { NSUInteger i = 0; NSMutableArray *data = [NSMutableArray new]; - NSArray *values = RCTPerformanceLoggerOutput(); - for (NSString *label in RCTPerformanceLoggerLabels()) { + RCTPerformanceLogger *performanceLogger = [_bridge performanceLogger]; + NSArray *values = [performanceLogger valuesForTags]; + for (NSString *label in [performanceLogger labelsForTags]) { long long value = values[i+1].longLongValue - values[i].longLongValue; NSString *unit = @"ms"; if ([label hasSuffix:@"Size"]) {