Refactor RCTPerformanceLogger to avoid having global state
Reviewed By: javache Differential Revision: D3509004 fbshipit-source-id: c4ab12b3f1defa32c2b1c211e775f6782ede4b7f
This commit is contained in:
parent
4f5c2b48fe
commit
97299260b6
|
@ -97,7 +97,7 @@ RCT_EXTERN NSArray<Class> *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<Class> *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<Class> *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<Class> *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<Class> *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<Class> *RCTGetModuleClasses(void);
|
|||
return;
|
||||
}
|
||||
}
|
||||
onSourceLoad(error, source);
|
||||
onSourceLoad(error, source, sourceLength);
|
||||
}];
|
||||
} else {
|
||||
// Allow testing without a script
|
||||
|
@ -190,7 +192,7 @@ RCT_EXTERN NSArray<Class> *RCTGetModuleClasses(void);
|
|||
postNotificationName:RCTJavaScriptDidLoadNotification
|
||||
object:_parentBridge userInfo:@{@"bridge": self}];
|
||||
});
|
||||
onSourceLoad(nil, nil);
|
||||
onSourceLoad(nil, nil, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -235,7 +237,7 @@ RCT_EXTERN NSArray<Class> *RCTGetModuleClasses(void);
|
|||
|
||||
- (void)initModulesWithDispatchGroup:(dispatch_group_t)dispatchGroup
|
||||
{
|
||||
RCTPerformanceLoggerStart(RCTPLNativeModuleInit);
|
||||
[_performanceLogger markStartForTag:RCTPLNativeModuleInit];
|
||||
|
||||
NSArray<id<RCTBridgeModule>> *extraModules = nil;
|
||||
if (self.delegate) {
|
||||
|
@ -382,7 +384,7 @@ RCT_EXTERN NSArray<Class> *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<Class> *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<Class> *RCTGetModuleClasses(void);
|
|||
|
||||
- (void)didFinishLoading
|
||||
{
|
||||
RCTPerformanceLoggerEnd(RCTPLBridgeStartup);
|
||||
[_performanceLogger markStopForTag:RCTPLBridgeStartup];
|
||||
_loading = NO;
|
||||
[_javaScriptExecutor executeBlockOnJavaScriptQueue:^{
|
||||
for (dispatch_block_t call in _pendingCalls) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -110,26 +110,36 @@ static RCTBridge *RCTCurrentBridgeInstance = nil;
|
|||
- (instancetype)initWithDelegate:(id<RCTBridgeDelegate>)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<RCTBridgeDelegate>)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];
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -9,8 +9,6 @@
|
|||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#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<NSNumber *> *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<NSNumber *> *)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<NSString *> *)labelsForTags;
|
||||
|
||||
@end
|
||||
|
|
|
@ -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<NSString *> *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<NSNumber *> *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 <RCTBridgeModule>
|
||||
|
||||
@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<NSNumber *> *)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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#import <JavaScriptCore/JavaScriptCore.h>
|
||||
|
||||
#import "RCTLog.h"
|
||||
#import "RCTPerformanceLogger.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
|
@ -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)
|
||||
|
|
|
@ -510,8 +510,9 @@ RCT_EXPORT_MODULE()
|
|||
{
|
||||
NSUInteger i = 0;
|
||||
NSMutableArray<NSString *> *data = [NSMutableArray new];
|
||||
NSArray<NSNumber *> *values = RCTPerformanceLoggerOutput();
|
||||
for (NSString *label in RCTPerformanceLoggerLabels()) {
|
||||
RCTPerformanceLogger *performanceLogger = [_bridge performanceLogger];
|
||||
NSArray<NSNumber *> *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"]) {
|
||||
|
|
Loading…
Reference in New Issue