[ReactNative] Better profiling API + Fix overlaping events
This commit is contained in:
parent
fde476f4e5
commit
fb1fa12e89
|
@ -22,6 +22,7 @@
|
|||
#import "RCTJavaScriptLoader.h"
|
||||
#import "RCTKeyCommands.h"
|
||||
#import "RCTLog.h"
|
||||
#import "RCTProfile.h"
|
||||
#import "RCTRedBox.h"
|
||||
#import "RCTRootView.h"
|
||||
#import "RCTSparseArray.h"
|
||||
|
@ -48,39 +49,6 @@ typedef NS_ENUM(NSUInteger, RCTBridgeFields) {
|
|||
*/
|
||||
#define BATCHED_BRIDGE 1
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
#define RCT_PROFILE_START() \
|
||||
_Pragma("clang diagnostic push") \
|
||||
_Pragma("clang diagnostic ignored \"-Wshadow\"") \
|
||||
NSTimeInterval __rct_profile_start = CACurrentMediaTime() \
|
||||
_Pragma("clang diagnostic pop")
|
||||
|
||||
#define RCT_PROFILE_END(cat, args, profileName...) \
|
||||
do { \
|
||||
if (_profile) { \
|
||||
[_profileLock lock]; \
|
||||
[_profile addObject:@{ \
|
||||
@"name": [@[profileName] componentsJoinedByString: @"_"], \
|
||||
@"cat": @ #cat, \
|
||||
@"ts": @((NSUInteger)((__rct_profile_start - _startingTime) * 1e6)), \
|
||||
@"dur": @((NSUInteger)((CACurrentMediaTime() - __rct_profile_start) * 1e6)), \
|
||||
@"ph": @"X", \
|
||||
@"pid": @([[NSProcessInfo processInfo] processIdentifier]), \
|
||||
@"tid": [[NSThread currentThread] description], \
|
||||
@"args": args ?: [NSNull null], \
|
||||
}]; \
|
||||
[_profileLock unlock]; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#else
|
||||
|
||||
#define RCT_PROFILE_START(...)
|
||||
#define RCT_PROFILE_END(...)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __LP64__
|
||||
typedef uint64_t RCTHeaderValue;
|
||||
typedef struct section_64 RCTHeaderSection;
|
||||
|
@ -230,8 +198,6 @@ static NSArray *RCTBridgeModuleClassesByModuleID(void)
|
|||
|
||||
@interface RCTBridge ()
|
||||
|
||||
@property (nonatomic, copy, readonly) NSArray *profile;
|
||||
|
||||
- (void)_invokeAndProcessModule:(NSString *)module
|
||||
method:(NSString *)method
|
||||
arguments:(NSArray *)args
|
||||
|
@ -250,6 +216,7 @@ static NSArray *RCTBridgeModuleClassesByModuleID(void)
|
|||
|
||||
@property (nonatomic, copy, readonly) NSString *moduleClassName;
|
||||
@property (nonatomic, copy, readonly) NSString *JSMethodName;
|
||||
@property (nonatomic, assign, readonly) SEL selector;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -805,10 +772,6 @@ static NSDictionary *RCTLocalModulesConfig()
|
|||
NSMutableArray *_scheduledCalls;
|
||||
RCTSparseArray *_scheduledCallbacks;
|
||||
BOOL _loading;
|
||||
|
||||
NSUInteger _startingTime;
|
||||
NSMutableArray *_profile;
|
||||
NSLock *_profileLock;
|
||||
}
|
||||
|
||||
static id<RCTJavaScriptExecutor> _latestJSExecutor;
|
||||
|
@ -1111,25 +1074,28 @@ static id<RCTJavaScriptExecutor> _latestJSExecutor;
|
|||
- (void)enqueueApplicationScript:(NSString *)script url:(NSURL *)url onComplete:(RCTJavaScriptCompleteBlock)onComplete
|
||||
{
|
||||
RCTAssert(onComplete != nil, @"onComplete block passed in should be non-nil");
|
||||
RCT_PROFILE_START();
|
||||
NSNumber *context = RCTGetExecutorID(_javaScriptExecutor);
|
||||
RCTProfileBeginEvent();
|
||||
[_javaScriptExecutor executeApplicationScript:script sourceURL:url onComplete:^(NSError *scriptLoadError) {
|
||||
RCT_PROFILE_END(js_call, scriptLoadError, @"initial_script");
|
||||
RCTProfileEndEvent(@"ApplicationScript", @"js_call,init", scriptLoadError);
|
||||
if (scriptLoadError) {
|
||||
onComplete(scriptLoadError);
|
||||
return;
|
||||
}
|
||||
|
||||
RCT_PROFILE_START();
|
||||
RCTProfileBeginEvent();
|
||||
NSNumber *context = RCTGetExecutorID(_javaScriptExecutor);
|
||||
[_javaScriptExecutor executeJSCall:@"BatchedBridge"
|
||||
method:@"flushedQueue"
|
||||
arguments:@[]
|
||||
context:context
|
||||
callback:^(id json, NSError *error) {
|
||||
RCT_PROFILE_END(js_call, error, @"initial_call", @"BatchedBridge.flushedQueue");
|
||||
RCT_PROFILE_START();
|
||||
RCTProfileEndEvent(@"FetchApplicationScriptCallbacks", @"js_call,init", @{
|
||||
@"json": json ?: [NSNull null],
|
||||
@"error": error ?: [NSNull null],
|
||||
});
|
||||
|
||||
[self _handleBuffer:json context:context];
|
||||
RCT_PROFILE_END(objc_call, json, @"batched_js_calls");
|
||||
|
||||
onComplete(error);
|
||||
}];
|
||||
}];
|
||||
|
@ -1140,7 +1106,7 @@ static id<RCTJavaScriptExecutor> _latestJSExecutor;
|
|||
- (void)_invokeAndProcessModule:(NSString *)module method:(NSString *)method arguments:(NSArray *)args context:(NSNumber *)context
|
||||
{
|
||||
#if BATCHED_BRIDGE
|
||||
RCT_PROFILE_START();
|
||||
RCTProfileBeginEvent();
|
||||
|
||||
if ([module isEqualToString:@"RCTEventEmitter"]) {
|
||||
for (NSDictionary *call in _scheduledCalls) {
|
||||
|
@ -1163,7 +1129,7 @@ static id<RCTJavaScriptExecutor> _latestJSExecutor;
|
|||
[_scheduledCalls addObject:call];
|
||||
}
|
||||
|
||||
RCT_PROFILE_END(js_call, args, @"schedule", module, method);
|
||||
RCTProfileEndEvent(@"enqueue_call", @"objc_call", call);
|
||||
}
|
||||
|
||||
- (void)_actuallyInvokeAndProcessModule:(NSString *)module method:(NSString *)method arguments:(NSArray *)args context:(NSNumber *)context
|
||||
|
@ -1171,15 +1137,9 @@ static id<RCTJavaScriptExecutor> _latestJSExecutor;
|
|||
#endif
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:RCTEnqueueNotification object:nil userInfo:nil];
|
||||
|
||||
NSString *moduleDotMethod = [NSString stringWithFormat:@"%@.%@", module, method];
|
||||
RCT_PROFILE_START();
|
||||
RCTJavaScriptCallback processResponse = ^(id json, NSError *error) {
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:RCTDequeueNotification object:nil userInfo:nil];
|
||||
RCT_PROFILE_END(js_call, args, moduleDotMethod);
|
||||
|
||||
RCT_PROFILE_START();
|
||||
[self _handleBuffer:json context:context];
|
||||
RCT_PROFILE_END(objc_call, json, @"batched_js_calls");
|
||||
};
|
||||
|
||||
[_javaScriptExecutor executeJSCall:module
|
||||
|
@ -1271,9 +1231,17 @@ static id<RCTJavaScriptExecutor> _latestJSExecutor;
|
|||
}
|
||||
RCTModuleMethod *method = methods[methodID];
|
||||
|
||||
// Look up module
|
||||
id module = self->_modulesByID[moduleID];
|
||||
if (!module) {
|
||||
RCTLogError(@"No module found for name '%@'", RCTModuleNamesByID[moduleID]);
|
||||
return NO;
|
||||
}
|
||||
|
||||
__weak RCTBridge *weakSelf = self;
|
||||
dispatch_queue_t queue = _queuesByID[moduleID];
|
||||
dispatch_async(queue ?: dispatch_get_main_queue(), ^{
|
||||
RCTProfileBeginEvent();
|
||||
__strong RCTBridge *strongSelf = weakSelf;
|
||||
|
||||
if (!strongSelf.isValid) {
|
||||
|
@ -1282,13 +1250,6 @@ static id<RCTJavaScriptExecutor> _latestJSExecutor;
|
|||
return;
|
||||
}
|
||||
|
||||
// Look up module
|
||||
id module = strongSelf->_modulesByID[moduleID];
|
||||
if (!module) {
|
||||
RCTLogError(@"No module found for name '%@'", RCTModuleNamesByID[moduleID]);
|
||||
return;
|
||||
}
|
||||
|
||||
@try {
|
||||
[method invokeWithBridge:strongSelf module:module arguments:params context:context];
|
||||
}
|
||||
|
@ -1298,6 +1259,12 @@ static id<RCTJavaScriptExecutor> _latestJSExecutor;
|
|||
@throw;
|
||||
}
|
||||
}
|
||||
|
||||
RCTProfileEndEvent(@"Invoke callback", @"objc_call", @{
|
||||
@"module": method.moduleClassName,
|
||||
@"method": method.JSMethodName,
|
||||
@"selector": NSStringFromSelector(method.selector),
|
||||
});
|
||||
});
|
||||
|
||||
return YES;
|
||||
|
@ -1305,7 +1272,8 @@ static id<RCTJavaScriptExecutor> _latestJSExecutor;
|
|||
|
||||
- (void)_update:(CADisplayLink *)displayLink
|
||||
{
|
||||
RCT_PROFILE_START();
|
||||
RCTProfileImmediateEvent(@"VSYNC", displayLink.timestamp, @"g");
|
||||
RCTProfileBeginEvent();
|
||||
|
||||
RCTFrameUpdate *frameUpdate = [[RCTFrameUpdate alloc] initWithDisplayLink:displayLink];
|
||||
for (id<RCTFrameUpdateObserver> observer in _frameUpdateObservers) {
|
||||
|
@ -1316,7 +1284,7 @@ static id<RCTJavaScriptExecutor> _latestJSExecutor;
|
|||
|
||||
[self _runScheduledCalls];
|
||||
|
||||
RCT_PROFILE_END(display_link, nil, @"main_thread");
|
||||
RCTProfileEndEvent(@"DispatchFrameUpdate", @"objc_call", nil);
|
||||
}
|
||||
|
||||
- (void)_runScheduledCalls
|
||||
|
@ -1382,23 +1350,12 @@ static id<RCTJavaScriptExecutor> _latestJSExecutor;
|
|||
RCTLogError(@"To run the profiler you must be running from the dev server");
|
||||
return;
|
||||
}
|
||||
_profileLock = [[NSLock alloc] init];
|
||||
_startingTime = CACurrentMediaTime();
|
||||
|
||||
[_profileLock lock];
|
||||
_profile = [[NSMutableArray alloc] init];
|
||||
[_profileLock unlock];
|
||||
RCTProfileInit();
|
||||
}
|
||||
|
||||
- (void)stopProfiling
|
||||
{
|
||||
[_profileLock lock];
|
||||
NSArray *profile = _profile;
|
||||
_profile = nil;
|
||||
[_profileLock unlock];
|
||||
_profileLock = nil;
|
||||
|
||||
NSString *log = RCTJSONStringify(profile, NULL);
|
||||
NSString *log = RCTProfileEnd();
|
||||
NSString *URLString = [NSString stringWithFormat:@"%@://%@:%@/profile", _bundleURL.scheme, _bundleURL.host, _bundleURL.port];
|
||||
NSURL *URL = [NSURL URLWithString:URLString];
|
||||
NSMutableURLRequest *URLRequest = [NSMutableURLRequest requestWithURL:URL];
|
||||
|
|
|
@ -11,14 +11,13 @@
|
|||
|
||||
#import "RCTBridge.h"
|
||||
#import "RCTLog.h"
|
||||
#import "RCTProfile.h"
|
||||
#import "RCTRootView.h"
|
||||
#import "RCTSourceCode.h"
|
||||
#import "RCTUtils.h"
|
||||
|
||||
@interface RCTBridge (Profiling)
|
||||
|
||||
@property (nonatomic, copy, readonly) NSArray *profile;
|
||||
|
||||
- (void)startProfiling;
|
||||
- (void)stopProfiling;
|
||||
|
||||
|
@ -94,7 +93,7 @@ RCT_EXPORT_MODULE()
|
|||
NSString *debugTitleChrome = _bridge.executorClass && _bridge.executorClass == NSClassFromString(@"RCTWebSocketExecutor") ? @"Disable Chrome Debugging" : @"Enable Chrome Debugging";
|
||||
NSString *debugTitleSafari = _bridge.executorClass && _bridge.executorClass == NSClassFromString(@"RCTWebViewExecutor") ? @"Disable Safari Debugging" : @"Enable Safari Debugging";
|
||||
NSString *liveReloadTitle = _liveReloadEnabled ? @"Disable Live Reload" : @"Enable Live Reload";
|
||||
NSString *profilingTitle = _bridge.profile ? @"Stop Profiling" : @"Start Profiling";
|
||||
NSString *profilingTitle = RCTProfileIsProfiling() ? @"Stop Profiling" : @"Start Profiling";
|
||||
|
||||
UIActionSheet *actionSheet =
|
||||
[[UIActionSheet alloc] initWithTitle:@"React Native: Development"
|
||||
|
@ -148,7 +147,7 @@ RCT_EXPORT_MODULE()
|
|||
}
|
||||
|
||||
_profilingEnabled = enabled;
|
||||
if (_bridge.profile) {
|
||||
if (RCTProfileIsProfiling()) {
|
||||
[_bridge stopProfiling];
|
||||
} else {
|
||||
[_bridge startProfiling];
|
||||
|
|
|
@ -45,6 +45,11 @@ typedef void (^RCTLogFunction)(
|
|||
NSString *message
|
||||
);
|
||||
|
||||
/**
|
||||
* Get a given thread's name (or the current queue, iff in debug mode)
|
||||
*/
|
||||
NSString *RCTThreadName(NSThread *);
|
||||
|
||||
/**
|
||||
* A method to generate a string from a collection of log data. To omit any
|
||||
* particular data from the log, just pass nil or zero for the argument.
|
||||
|
|
|
@ -98,6 +98,22 @@ void RCTPerformBlockWithLogPrefix(void (^block)(void), NSString *prefix)
|
|||
[prefixStack removeLastObject];
|
||||
}
|
||||
|
||||
NSString *RCTThreadName(NSThread *thread)
|
||||
{
|
||||
NSString *threadName = [thread isMainThread] ? @"main" : thread.name;
|
||||
if (threadName.length == 0) {
|
||||
#if DEBUG
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
threadName = @(dispatch_queue_get_label(dispatch_get_current_queue()));
|
||||
#pragma clang diagnostic pop
|
||||
#else
|
||||
threadName = [NSString stringWithFormat:@"%p", thread];
|
||||
#endif
|
||||
}
|
||||
return threadName;
|
||||
}
|
||||
|
||||
NSString *RCTFormatLog(
|
||||
NSDate *timestamp,
|
||||
NSThread *thread,
|
||||
|
@ -121,18 +137,7 @@ NSString *RCTFormatLog(
|
|||
[log appendFormat:@"[%s]", RCTLogLevels[level - 1]];
|
||||
}
|
||||
if (thread) {
|
||||
NSString *threadName = [thread isMainThread] ? @"main" : thread.name;
|
||||
if (threadName.length == 0) {
|
||||
#if DEBUG
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
threadName = @(dispatch_queue_get_label(dispatch_get_current_queue()));
|
||||
#pragma clang diagnostic pop
|
||||
#else
|
||||
threadName = [NSString stringWithFormat:@"%p", thread];
|
||||
#endif
|
||||
}
|
||||
[log appendFormat:@"[tid:%@]", threadName];
|
||||
[log appendFormat:@"[tid:%@]", RCTThreadName(thread)];
|
||||
}
|
||||
if (fileName) {
|
||||
fileName = [fileName lastPathComponent];
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/**
|
||||
* RCTProfile
|
||||
*
|
||||
* This file provides a set of functions and macros for performance profiling
|
||||
*
|
||||
* NOTE: This API is a work in a work in progress, please consider it before
|
||||
* before using.
|
||||
*/
|
||||
|
||||
#if DEBUG
|
||||
|
||||
/**
|
||||
* Returns YES if the profiling information is currently being collected
|
||||
*/
|
||||
BOOL RCTProfileIsProfiling(void);
|
||||
|
||||
/**
|
||||
* Start collecting profiling information
|
||||
*/
|
||||
void RCTProfileInit(void);
|
||||
|
||||
/**
|
||||
* Stop profiling and return a JSON string of the collected data - The data
|
||||
* returned is compliant with google's trace event format - the format used
|
||||
* as input to trace-viewer
|
||||
*/
|
||||
NSString *RCTProfileEnd(void);
|
||||
|
||||
/**
|
||||
* Collects the initial event information for the event and returns a reference ID
|
||||
*/
|
||||
NSNumber *_RCTProfileBeginEvent(void);
|
||||
|
||||
/**
|
||||
* The ID returned by BeginEvent should then be passed into EndEvent, with the
|
||||
* rest of the event information. Just at this point the event will actually be
|
||||
* registered
|
||||
*/
|
||||
void _RCTProfileEndEvent(NSNumber *, NSString *, NSString *, id);
|
||||
|
||||
/**
|
||||
* This pair of macros implicitly handle the event ID when beginning and ending
|
||||
* an event, for both simplicity and performance reasons, this method is preferred
|
||||
*
|
||||
* NOTE: The EndEvent call has to be either, in the same scope of BeginEvent,
|
||||
* or in a sub-scope, otherwise the ID stored by BeginEvent won't be accessible
|
||||
* for EndEvent, in this case you may want to use the actual C functions.
|
||||
*/
|
||||
#define RCTProfileBeginEvent() \
|
||||
_Pragma("clang diagnostic push") \
|
||||
_Pragma("clang diagnostic ignored \"-Wshadow\"") \
|
||||
NSNumber *__rct_profile_id = _RCTProfileBeginEvent(); \
|
||||
_Pragma("clang diagnostic pop")
|
||||
|
||||
#define RCTProfileEndEvent(name, category, args...) \
|
||||
_RCTProfileEndEvent(__rct_profile_id, name, category, args)
|
||||
|
||||
/**
|
||||
* An event that doesn't have a duration (i.e. Notification, VSync, etc)
|
||||
*/
|
||||
void RCTProfileImmediateEvent(NSString *, NSTimeInterval , NSString *);
|
||||
|
||||
/**
|
||||
* Helper to profile the duration of the execution of a block. This method uses
|
||||
* self and _cmd to name this event for simplicity sake.
|
||||
*
|
||||
* NOTE: The block can't expect any argument
|
||||
*/
|
||||
#define RCTProfileBlock(block, category, arguments) \
|
||||
^{ \
|
||||
RCTProfileBeginEvent(); \
|
||||
block(); \
|
||||
RCTProfileEndEvent([NSString stringWithFormat:@"[%@ %@]", NSStringFromClass([self class]), NSStringFromSelector(_cmd)], category, arguments); \
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define RCTProfileIsProfiling(...) NO
|
||||
#define RCTProfileInit(...)
|
||||
#define RCTProfileEnd(...) @""
|
||||
|
||||
#define _RCTProfileBeginEvent(...) @0
|
||||
#define RCTProfileBeginEvent(...)
|
||||
|
||||
#define _RCTProfileEndEvent(...)
|
||||
#define RCTProfileEndEvent(...)
|
||||
|
||||
#define RCTProfileImmediateEvent(...)
|
||||
|
||||
#define RCTProfileBlock(block, ...) block
|
||||
|
||||
#endif
|
|
@ -0,0 +1,149 @@
|
|||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import "RCTProfile.h"
|
||||
|
||||
#import <mach/mach.h>
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "RCTLog.h"
|
||||
#import "RCTUtils.h"
|
||||
|
||||
#pragma mark - Prototypes
|
||||
|
||||
NSNumber *RCTProfileTimestamp(NSTimeInterval);
|
||||
NSString *RCTProfileMemory(vm_size_t);
|
||||
NSDictionary *RCTProfileGetMemoryUsage(void);
|
||||
|
||||
#pragma mark - Constants
|
||||
|
||||
NSString const *RCTProfileTraceEvents = @"traceEvents";
|
||||
NSString const *RCTProfileSamples = @"samples";
|
||||
|
||||
#pragma mark - Variables
|
||||
|
||||
NSDictionary *RCTProfileInfo;
|
||||
NSUInteger RCTProfileEventID = 0;
|
||||
NSMutableDictionary *RCTProfileOngoingEvents;
|
||||
NSTimeInterval RCTProfileStartTime;
|
||||
|
||||
#pragma mark - Macros
|
||||
|
||||
#define RCTProfileAddEvent(type, props...) \
|
||||
[RCTProfileInfo[type] addObject:@{ \
|
||||
@"pid": @([[NSProcessInfo processInfo] processIdentifier]), \
|
||||
@"tid": RCTThreadName([NSThread currentThread]), \
|
||||
props \
|
||||
}];
|
||||
|
||||
#define CHECK(...) \
|
||||
if (!RCTProfileIsProfiling()) { \
|
||||
return __VA_ARGS__; \
|
||||
}
|
||||
|
||||
#pragma mark - Private Helpers
|
||||
|
||||
NSNumber *RCTProfileTimestamp(NSTimeInterval timestamp)
|
||||
{
|
||||
return @((timestamp - RCTProfileStartTime) * 1e6);
|
||||
}
|
||||
|
||||
NSString *RCTProfileMemory(vm_size_t memory)
|
||||
{
|
||||
double mem = ((double)memory) / 1024 / 1024;
|
||||
return [NSString stringWithFormat:@"%.2lfmb", mem];
|
||||
}
|
||||
|
||||
NSDictionary *RCTProfileGetMemoryUsage(void)
|
||||
{
|
||||
CHECK(@{});
|
||||
struct task_basic_info info;
|
||||
mach_msg_type_number_t size = sizeof(info);
|
||||
kern_return_t kerr = task_info(mach_task_self(),
|
||||
TASK_BASIC_INFO,
|
||||
(task_info_t)&info,
|
||||
&size);
|
||||
if( kerr == KERN_SUCCESS ) {
|
||||
return @{
|
||||
@"suspend_count": @(info.suspend_count),
|
||||
@"virtual_size": RCTProfileMemory(info.virtual_size),
|
||||
@"resident_size": RCTProfileMemory(info.resident_size),
|
||||
};
|
||||
} else {
|
||||
return @{};
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Public Functions
|
||||
|
||||
BOOL RCTProfileIsProfiling(void)
|
||||
{
|
||||
return RCTProfileInfo != nil;
|
||||
}
|
||||
|
||||
void RCTProfileInit(void)
|
||||
{
|
||||
RCTProfileStartTime = CACurrentMediaTime();
|
||||
RCTProfileOngoingEvents = [[NSMutableDictionary alloc] init];
|
||||
RCTProfileInfo = @{
|
||||
RCTProfileTraceEvents: [[NSMutableArray alloc] init],
|
||||
RCTProfileSamples: [[NSMutableArray alloc] init],
|
||||
};
|
||||
}
|
||||
|
||||
NSString *RCTProfileEnd(void)
|
||||
{
|
||||
NSString *log = RCTJSONStringify(RCTProfileInfo, NULL);
|
||||
RCTProfileEventID = 0;
|
||||
RCTProfileInfo = nil;
|
||||
RCTProfileOngoingEvents = nil;
|
||||
return log;
|
||||
}
|
||||
|
||||
NSNumber *_RCTProfileBeginEvent(void)
|
||||
{
|
||||
CHECK(@0);
|
||||
NSNumber *eventID = @(++RCTProfileEventID);
|
||||
RCTProfileOngoingEvents[eventID] = RCTProfileTimestamp(CACurrentMediaTime());
|
||||
return eventID;
|
||||
}
|
||||
|
||||
void _RCTProfileEndEvent(NSNumber *eventID, NSString *name, NSString *categories, id args)
|
||||
{
|
||||
CHECK();
|
||||
NSNumber *startTimestamp = RCTProfileOngoingEvents[eventID];
|
||||
if (!startTimestamp) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSNumber *endTimestamp = RCTProfileTimestamp(CACurrentMediaTime());
|
||||
|
||||
RCTProfileAddEvent(RCTProfileTraceEvents,
|
||||
@"name": name,
|
||||
@"cat": categories,
|
||||
@"ph": @"X",
|
||||
@"ts": startTimestamp,
|
||||
@"dur": @(endTimestamp.doubleValue - startTimestamp.doubleValue),
|
||||
@"args": args ?: @[],
|
||||
);
|
||||
[RCTProfileOngoingEvents removeObjectForKey:eventID];
|
||||
}
|
||||
|
||||
void RCTProfileImmediateEvent(NSString *name, NSTimeInterval timestamp, NSString *scope)
|
||||
{
|
||||
CHECK();
|
||||
RCTProfileAddEvent(RCTProfileTraceEvents,
|
||||
@"name": name,
|
||||
@"ts": RCTProfileTimestamp(timestamp),
|
||||
@"scope": scope,
|
||||
@"ph": @"i",
|
||||
@"args": RCTProfileGetMemoryUsage(),
|
||||
);
|
||||
}
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#import "RCTAssert.h"
|
||||
#import "RCTLog.h"
|
||||
#import "RCTProfile.h"
|
||||
#import "RCTUtils.h"
|
||||
|
||||
@interface RCTJavaScriptContext : NSObject <RCTInvalidating>
|
||||
|
@ -234,7 +235,7 @@ static NSError *RCTNSErrorFromJSError(JSContextRef context, JSValueRef jsError)
|
|||
{
|
||||
RCTAssert(onComplete != nil, @"onComplete block should not be nil");
|
||||
__weak RCTContextExecutor *weakSelf = self;
|
||||
[self executeBlockOnJavaScriptQueue:^{
|
||||
[self executeBlockOnJavaScriptQueue:RCTProfileBlock((^{
|
||||
RCTContextExecutor *strongSelf = weakSelf;
|
||||
if (!strongSelf || !strongSelf.isValid || ![RCTGetExecutorID(strongSelf) isEqualToNumber:executorID]) {
|
||||
return;
|
||||
|
@ -275,7 +276,7 @@ static NSError *RCTNSErrorFromJSError(JSContextRef context, JSValueRef jsError)
|
|||
}
|
||||
|
||||
onComplete(objcValue, nil);
|
||||
}];
|
||||
}), @"js_call", (@{@"module":name, @"method": method, @"args": arguments}))];
|
||||
}
|
||||
|
||||
- (void)executeApplicationScript:(NSString *)script
|
||||
|
@ -285,7 +286,7 @@ static NSError *RCTNSErrorFromJSError(JSContextRef context, JSValueRef jsError)
|
|||
RCTAssert(sourceURL != nil, @"url should not be nil");
|
||||
|
||||
__weak RCTContextExecutor *weakSelf = self;
|
||||
[self executeBlockOnJavaScriptQueue:^{
|
||||
[self executeBlockOnJavaScriptQueue:RCTProfileBlock((^{
|
||||
RCTContextExecutor *strongSelf = weakSelf;
|
||||
if (!strongSelf || !strongSelf.isValid) {
|
||||
return;
|
||||
|
@ -304,7 +305,7 @@ static NSError *RCTNSErrorFromJSError(JSContextRef context, JSValueRef jsError)
|
|||
}
|
||||
onComplete(error);
|
||||
}
|
||||
}];
|
||||
}), @"js_call", (@{ @"url": sourceURL }))];
|
||||
}
|
||||
|
||||
- (void)executeBlockOnJavaScriptQueue:(dispatch_block_t)block
|
||||
|
@ -327,7 +328,7 @@ static NSError *RCTNSErrorFromJSError(JSContextRef context, JSValueRef jsError)
|
|||
#endif
|
||||
|
||||
__weak RCTContextExecutor *weakSelf = self;
|
||||
[self executeBlockOnJavaScriptQueue:^{
|
||||
[self executeBlockOnJavaScriptQueue:RCTProfileBlock((^{
|
||||
RCTContextExecutor *strongSelf = weakSelf;
|
||||
if (!strongSelf || !strongSelf.isValid) {
|
||||
return;
|
||||
|
@ -354,7 +355,7 @@ static NSError *RCTNSErrorFromJSError(JSContextRef context, JSValueRef jsError)
|
|||
if (onComplete) {
|
||||
onComplete(nil);
|
||||
}
|
||||
}];
|
||||
}), @"js_call,json_call", (@{@"objectName": objectName}))];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#import "RCTBridge.h"
|
||||
#import "RCTConvert.h"
|
||||
#import "RCTLog.h"
|
||||
#import "RCTProfile.h"
|
||||
#import "RCTRootView.h"
|
||||
#import "RCTScrollableProtocol.h"
|
||||
#import "RCTShadowView.h"
|
||||
|
@ -888,9 +889,13 @@ RCT_EXPORT_METHOD(blur:(NSNumber *)reactTag)
|
|||
|
||||
// Execute the previously queued UI blocks
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
RCTProfileBeginEvent();
|
||||
for (dispatch_block_t block in previousPendingUIBlocks) {
|
||||
block();
|
||||
}
|
||||
RCTProfileEndEvent(@"UIManager flushUIBlocks", @"objc_call", @{
|
||||
@"count": @(previousPendingUIBlocks.count),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
14F3620D1AABD06A001CE568 /* RCTSwitch.m in Sources */ = {isa = PBXBuildFile; fileRef = 14F362081AABD06A001CE568 /* RCTSwitch.m */; };
|
||||
14F3620E1AABD06A001CE568 /* RCTSwitchManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 14F3620A1AABD06A001CE568 /* RCTSwitchManager.m */; };
|
||||
14F484561AABFCE100FDF6B9 /* RCTSliderManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 14F484551AABFCE100FDF6B9 /* RCTSliderManager.m */; };
|
||||
14F4D38B1AE1B7E40049C042 /* RCTProfile.m in Sources */ = {isa = PBXBuildFile; fileRef = 14F4D38A1AE1B7E40049C042 /* RCTProfile.m */; };
|
||||
58114A161AAE854800E7D092 /* RCTPicker.m in Sources */ = {isa = PBXBuildFile; fileRef = 58114A131AAE854800E7D092 /* RCTPicker.m */; };
|
||||
58114A171AAE854800E7D092 /* RCTPickerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 58114A151AAE854800E7D092 /* RCTPickerManager.m */; };
|
||||
58114A501AAE93D500E7D092 /* RCTAsyncLocalStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = 58114A4E1AAE93D500E7D092 /* RCTAsyncLocalStorage.m */; };
|
||||
|
@ -165,6 +166,8 @@
|
|||
14F3620A1AABD06A001CE568 /* RCTSwitchManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTSwitchManager.m; sourceTree = "<group>"; };
|
||||
14F484541AABFCE100FDF6B9 /* RCTSliderManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTSliderManager.h; sourceTree = "<group>"; };
|
||||
14F484551AABFCE100FDF6B9 /* RCTSliderManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTSliderManager.m; sourceTree = "<group>"; };
|
||||
14F4D3891AE1B7E40049C042 /* RCTProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTProfile.h; sourceTree = "<group>"; };
|
||||
14F4D38A1AE1B7E40049C042 /* RCTProfile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTProfile.m; sourceTree = "<group>"; };
|
||||
58114A121AAE854800E7D092 /* RCTPicker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTPicker.h; sourceTree = "<group>"; };
|
||||
58114A131AAE854800E7D092 /* RCTPicker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTPicker.m; sourceTree = "<group>"; };
|
||||
58114A141AAE854800E7D092 /* RCTPickerManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTPickerManager.h; sourceTree = "<group>"; };
|
||||
|
@ -393,6 +396,8 @@
|
|||
83CBBA4F1A601E3B00E9B192 /* RCTUtils.h */,
|
||||
83CBBA501A601E3B00E9B192 /* RCTUtils.m */,
|
||||
1436DD071ADE7AA000A5ED7D /* RCTFrameUpdate.h */,
|
||||
14F4D3891AE1B7E40049C042 /* RCTProfile.h */,
|
||||
14F4D38A1AE1B7E40049C042 /* RCTProfile.m */,
|
||||
);
|
||||
path = Base;
|
||||
sourceTree = "<group>";
|
||||
|
@ -483,6 +488,7 @@
|
|||
83CBBA511A601E3B00E9B192 /* RCTAssert.m in Sources */,
|
||||
58114A501AAE93D500E7D092 /* RCTAsyncLocalStorage.m in Sources */,
|
||||
832348161A77A5AA00B55238 /* Layout.c in Sources */,
|
||||
14F4D38B1AE1B7E40049C042 /* RCTProfile.m in Sources */,
|
||||
14F3620D1AABD06A001CE568 /* RCTSwitch.m in Sources */,
|
||||
14F3620E1AABD06A001CE568 /* RCTSwitchManager.m in Sources */,
|
||||
13B080201A69489C00A75B9A /* RCTUIActivityIndicatorViewManager.m in Sources */,
|
||||
|
|
Loading…
Reference in New Issue