[ReactNative] Change RCTProfile API to be compatible with systrace

This commit is contained in:
Tadeu Zagallo 2015-08-19 23:36:11 -07:00
parent 16ddb1962a
commit 81fdf3e532
6 changed files with 187 additions and 112 deletions

View File

@ -29,9 +29,9 @@ var BridgeProfiling = {
}
},
profileEnd(profileName?: string) {
profileEnd() {
if (GLOBAL.__BridgeProfilingIsProfiling) {
console.profileEnd(profileName);
console.profileEnd();
}
},
@ -41,14 +41,14 @@ var BridgeProfiling = {
ReactPerf.measure = function (objName, fnName, func) {
func = originalMeasure.call(ReactPerf, objName, fnName, func);
return function (component) {
BridgeProfiling.profile();
var ret = func.apply(this, arguments);
if (GLOBAL.__BridgeProfilingIsProfiling) {
var name = this._instance && this._instance.constructor &&
(this._instance.constructor.displayName ||
this._instance.constructor.name);
BridgeProfiling.profileEnd(`${objName}.${fnName}(${name})`);
BridgeProfiling.profile(`${objName}.${fnName}(${name})`);
}
var ret = func.apply(this, arguments);
BridgeProfiling.profileEnd();
return ret;
};
};

View File

@ -167,11 +167,11 @@ id<RCTJavaScriptExecutor> RCTGetLatestExecutor(void)
- (void)loadSource:(RCTSourceLoadBlock)_onSourceLoad
{
RCTPerformanceLoggerStart(RCTPLScriptDownload);
RCTProfileBeginEvent();
int cookie = RCTProfileBeginAsyncEvent(0, @"JavaScript download", nil);
RCTSourceLoadBlock onSourceLoad = ^(NSError *error, NSString *source) {
RCTPerformanceLoggerEnd(RCTPLScriptDownload);
RCTProfileEndEvent(@"JavaScript download", @"init,download", @[]);
RCTProfileEndAsyncEvent(0, @"init,download", cookie, @"JavaScript download", nil);
if (error) {
NSArray *stack = [error userInfo][@"stack"];
@ -517,7 +517,9 @@ RCT_NOT_IMPLEMENTED(-initWithBundleURL:(__unused NSURL *)bundleURL
}
}
- (void)enqueueApplicationScript:(NSString *)script url:(NSURL *)url onComplete:(RCTJavaScriptCompleteBlock)onComplete
- (void)enqueueApplicationScript:(NSString *)script
url:(NSURL *)url
onComplete:(RCTJavaScriptCompleteBlock)onComplete
{
RCTAssert(onComplete != nil, @"onComplete block passed in should be non-nil");
@ -531,20 +533,21 @@ RCT_NOT_IMPLEMENTED(-initWithBundleURL:(__unused NSURL *)bundleURL
return;
}
RCTProfileBeginEvent();
RCTProfileBeginEvent(0, @"FetchApplicationScriptCallbacks", nil);
[_javaScriptExecutor executeJSCall:@"BatchedBridge"
method:@"flushedQueue"
arguments:@[]
callback:^(id json, NSError *error) {
RCTProfileEndEvent(@"FetchApplicationScriptCallbacks", @"js_call,init", @{
@"json": RCTNullIfNil(json),
@"error": RCTNullIfNil(error),
});
callback:^(id json, NSError *error)
{
RCTProfileEndEvent(0, @"js_call,init", @{
@"json": RCTNullIfNil(json),
@"error": RCTNullIfNil(error),
});
[self _handleBuffer:json];
[self _handleBuffer:json];
onComplete(error);
}];
onComplete(error);
}];
}];
}
@ -565,7 +568,7 @@ RCT_NOT_IMPLEMENTED(-initWithBundleURL:(__unused NSURL *)bundleURL
__weak RCTBatchedBridge *weakSelf = self;
[_javaScriptExecutor executeBlockOnJavaScriptQueue:^{
RCTProfileEndFlowEvent();
RCTProfileBeginEvent();
RCTProfileBeginEvent(0, @"enqueue_call", nil);
RCTBatchedBridge *strongSelf = weakSelf;
if (!strongSelf.isValid || !strongSelf->_scheduledCallbacks || !strongSelf->_scheduledCalls) {
@ -588,11 +591,13 @@ RCT_NOT_IMPLEMENTED(-initWithBundleURL:(__unused NSURL *)bundleURL
[strongSelf->_scheduledCalls addObject:call];
}
RCTProfileEndEvent(@"enqueue_call", @"objc_call", call);
RCTProfileEndEvent(0, @"objc_call", call);
}];
}
- (void)_actuallyInvokeAndProcessModule:(NSString *)module method:(NSString *)method arguments:(NSArray *)args
- (void)_actuallyInvokeAndProcessModule:(NSString *)module
method:(NSString *)method
arguments:(NSArray *)args
{
RCTAssertJSThread();
@ -678,7 +683,7 @@ RCT_NOT_IMPLEMENTED(-initWithBundleURL:(__unused NSURL *)bundleURL
[moduleData dispatchBlock:^{
RCTProfileEndFlowEvent();
RCTProfileBeginEvent();
RCTProfileBeginEvent(0, RCTCurrentThreadName(), nil);
NSOrderedSet *calls = [buckets objectForKey:moduleData];
@autoreleasepool {
@ -691,7 +696,9 @@ RCT_NOT_IMPLEMENTED(-initWithBundleURL:(__unused NSURL *)bundleURL
}
}
RCTProfileEndEvent(RCTCurrentThreadName(), @"objc_call,dispatch_async", @{ @"calls": @(calls.count) });
RCTProfileEndEvent(0, @"objc_call,dispatch_async", @{
@"calls": @(calls.count),
});
}];
}
@ -719,7 +726,7 @@ RCT_NOT_IMPLEMENTED(-initWithBundleURL:(__unused NSURL *)bundleURL
return NO;
}
RCTProfileBeginEvent();
RCTProfileBeginEvent(0, @"Invoke callback", nil);
RCTModuleData *moduleData = _moduleDataByID[moduleID];
if (RCT_DEBUG && !moduleData) {
@ -743,7 +750,7 @@ RCT_NOT_IMPLEMENTED(-initWithBundleURL:(__unused NSURL *)bundleURL
}
}
RCTProfileEndEvent(@"Invoke callback", @"objc_call", @{
RCTProfileEndEvent(0, @"objc_call", @{
@"module": NSStringFromClass(method.moduleClass),
@"method": method.JSMethodName,
@"selector": NSStringFromSelector(method.selector),
@ -756,7 +763,7 @@ RCT_NOT_IMPLEMENTED(-initWithBundleURL:(__unused NSURL *)bundleURL
- (void)_jsThreadUpdate:(CADisplayLink *)displayLink
{
RCTAssertJSThread();
RCTProfileBeginEvent();
RCTProfileBeginEvent(0, @"DispatchFrameUpdate", nil);
RCTFrameUpdate *frameUpdate = [[RCTFrameUpdate alloc] initWithDisplayLink:displayLink];
for (RCTModuleData *moduleData in _frameUpdateObservers) {
@ -767,9 +774,9 @@ RCT_NOT_IMPLEMENTED(-initWithBundleURL:(__unused NSURL *)bundleURL
[moduleData dispatchBlock:^{
RCTProfileEndFlowEvent();
RCTProfileBeginEvent();
RCTProfileBeginEvent(0, name, nil);
[observer didUpdateFrame:frameUpdate];
RCTProfileEndEvent(name, @"objc_call,fps", nil);
RCTProfileEndEvent(0, @"objc_call,fps", nil);
}];
}
}
@ -777,7 +784,7 @@ RCT_NOT_IMPLEMENTED(-initWithBundleURL:(__unused NSURL *)bundleURL
NSArray *calls = [_scheduledCallbacks.allObjects arrayByAddingObjectsFromArray:_scheduledCalls];
RCT_IF_DEV(
RCTProfileImmediateEvent(@"JS Thread Tick", displayLink.timestamp, @"g");
RCTProfileImmediateEvent(0, @"JS Thread Tick", 'g');
for (NSDictionary *call in calls) {
_RCTProfileEndFlowEvent(call[@"call_id"]);
@ -792,7 +799,7 @@ RCT_NOT_IMPLEMENTED(-initWithBundleURL:(__unused NSURL *)bundleURL
arguments:@[[calls valueForKey:@"js_args"]]];
}
RCTProfileEndEvent(@"DispatchFrameUpdate", @"objc_call", nil);
RCTProfileEndEvent(0, @"objc_call", nil);
dispatch_async(dispatch_get_main_queue(), ^{
[self.perfStats.jsGraph onTick:displayLink.timestamp];
@ -803,7 +810,7 @@ RCT_NOT_IMPLEMENTED(-initWithBundleURL:(__unused NSURL *)bundleURL
{
RCTAssertMainThread();
RCTProfileImmediateEvent(@"VSYNC", displayLink.timestamp, @"g");
RCTProfileImmediateEvent(0, @"VSYNC", 'g');
_modulesByName == nil ?: [self.perfStats.uiGraph onTick:displayLink.timestamp];
}

View File

@ -59,36 +59,42 @@ RCT_EXTERN NSString *RCTProfileEnd(RCTBridge *);
/**
* Collects the initial event information for the event and returns a reference ID
*/
RCT_EXTERN NSNumber *_RCTProfileBeginEvent(void);
RCT_EXTERN void RCTProfileBeginEvent(uint64_t tag,
NSString *name,
NSDictionary *args);
/**
* 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
*/
RCT_EXTERN void _RCTProfileEndEvent(NSNumber *, NSString *, NSString *, id);
RCT_EXTERN void RCTProfileEndEvent(uint64_t tag,
NSString *category,
NSDictionary *args);
/**
* 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.
* Collects the initial event information for the event and returns a reference ID
*/
#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)
RCT_EXTERN int RCTProfileBeginAsyncEvent(uint64_t tag,
NSString *name,
NSDictionary *args);
/**
* 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
*/
RCT_EXTERN void RCTProfileEndAsyncEvent(uint64_t tag,
NSString *category,
int cookie,
NSString *name,
NSDictionary *args);
/**
* An event that doesn't have a duration (i.e. Notification, VSync, etc)
*/
RCT_EXTERN void RCTProfileImmediateEvent(NSString *, NSTimeInterval , NSString *);
RCT_EXTERN void RCTProfileImmediateEvent(uint64_t tag,
NSString *name,
char scope);
/**
* Helper to profile the duration of the execution of a block. This method uses
@ -96,11 +102,11 @@ RCT_EXTERN void RCTProfileImmediateEvent(NSString *, NSTimeInterval , NSString *
*
* NOTE: The block can't expect any argument
*/
#define RCTProfileBlock(block, category, arguments) \
#define RCTProfileBlock(block, tag, category, arguments) \
^{ \
RCTProfileBeginEvent(); \
RCTProfileBeginEvent(tag, @(__PRETTY_FUNCTION__), nil); \
block(); \
RCTProfileEndEvent([NSString stringWithFormat:@"[%@ %@]", NSStringFromClass([self class]), NSStringFromSelector(_cmd)], category, arguments); \
RCTProfileEndEvent(tag, category, arguments); \
}
/**
@ -125,12 +131,12 @@ RCT_EXTERN void RCTProfileUnhookModules(RCTBridge *);
#define RCTProfileInit(...)
#define RCTProfileEnd(...) @""
#define _RCTProfileBeginEvent(...) @0
#define RCTProfileBeginEvent(...)
#define _RCTProfileEndEvent(...)
#define RCTProfileEndEvent(...)
#define RCTProfileBeginAsyncEvent(...) 0
#define RCTProfileEndAsyncEvent(...)
#define RCTProfileImmediateEvent(...)
#define RCTProfileBlock(block, ...) block

View File

@ -26,12 +26,6 @@ NSString *const RCTProfileDidEndProfiling = @"RCTProfileDidEndProfiling";
#if RCT_DEV
#pragma mark - Prototypes
NSNumber *RCTProfileTimestamp(NSTimeInterval);
NSString *RCTProfileMemory(vm_size_t);
NSDictionary *RCTProfileGetMemoryUsage(void);
#pragma mark - Constants
NSString const *RCTProfileTraceEvents = @"traceEvents";
@ -67,18 +61,18 @@ __VA_ARGS__ \
#pragma mark - Private Helpers
NSNumber *RCTProfileTimestamp(NSTimeInterval timestamp)
static NSNumber *RCTProfileTimestamp(NSTimeInterval timestamp)
{
return @((timestamp - RCTProfileStartTime) * 1e6);
}
NSString *RCTProfileMemory(vm_size_t memory)
static NSString *RCTProfileMemory(vm_size_t memory)
{
double mem = ((double)memory) / 1024 / 1024;
return [NSString stringWithFormat:@"%.2lfmb", mem];
}
NSDictionary *RCTProfileGetMemoryUsage(void)
static NSDictionary *RCTProfileGetMemoryUsage(void)
{
struct task_basic_info info;
mach_msg_type_number_t size = sizeof(info);
@ -97,6 +91,22 @@ NSDictionary *RCTProfileGetMemoryUsage(void)
}
}
static NSDictionary *RCTProfileMergeArgs(NSDictionary *args0, NSDictionary *args1)
{
args0 = RCTNilIfNull(args0);
args1 = RCTNilIfNull(args1);
if (!args0 && args1) {
args0 = args1;
} else if (args0 && args1) {
NSMutableDictionary *d = [args0 mutableCopy];
[d addEntriesFromDictionary:args1];
args0 = [d copy];
}
return RCTNullIfNil(args0);
}
#pragma mark - Module hooks
static const char *RCTProfileProxyClassName(Class);
@ -120,9 +130,9 @@ static void RCTProfileForwardInvocation(NSObject *self, __unused SEL cmd, NSInvo
if ([object_getClass(self) instancesRespondToSelector:newSel]) {
invocation.selector = newSel;
RCTProfileBeginEvent();
RCTProfileBeginEvent(0, name, nil);
[invocation invoke];
RCTProfileEndEvent(name, @"objc_call,modules,auto", nil);
RCTProfileEndEvent(0, @"objc_call,modules,auto", nil);
} else if ([self respondsToSelector:invocation.selector]) {
[invocation invoke];
} else {
@ -248,45 +258,116 @@ NSString *RCTProfileEnd(RCTBridge *bridge)
return log;
}
NSNumber *_RCTProfileBeginEvent(void)
static NSMutableArray *RCTProfileGetThreadEvents(void)
{
CHECK(@0);
RCTProfileLock(
NSNumber *eventID = @(++RCTProfileEventID);
RCTProfileOngoingEvents[eventID] = RCTProfileTimestamp(CACurrentMediaTime());
);
return eventID;
static NSString *const RCTProfileThreadEventsKey = @"RCTProfileThreadEventsKey";
NSMutableArray *threadEvents = [NSThread currentThread].threadDictionary[RCTProfileThreadEventsKey];
if (!threadEvents) {
threadEvents = [[NSMutableArray alloc] init];
[NSThread currentThread].threadDictionary[RCTProfileThreadEventsKey] = threadEvents;
}
return threadEvents;
}
void _RCTProfileEndEvent(NSNumber *eventID, NSString *name, NSString *categories, id args)
void RCTProfileBeginEvent(uint64_t tag, NSString *name, NSDictionary *args)
{
CHECK();
NSMutableArray *events = RCTProfileGetThreadEvents();
[events addObject:@[
RCTProfileTimestamp(CACurrentMediaTime()),
@(tag),
name,
RCTNullIfNil(args),
]];
}
void RCTProfileEndEvent(
__unused uint64_t tag,
NSString *category,
NSDictionary *args
) {
CHECK();
NSMutableArray *events = RCTProfileGetThreadEvents();
NSArray *event = [events lastObject];
[events removeLastObject];
if (!event) {
return;
}
NSNumber *start = event[0];
RCTProfileLock(
NSNumber *startTimestamp = RCTProfileOngoingEvents[eventID];
if (startTimestamp) {
RCTProfileAddEvent(RCTProfileTraceEvents,
@"name": event[2],
@"cat": category,
@"ph": @"X",
@"ts": start,
@"dur": @(RCTProfileTimestamp(CACurrentMediaTime()).doubleValue - start.doubleValue),
@"args": RCTProfileMergeArgs(event[3], args),
);
);
}
int RCTProfileBeginAsyncEvent(
__unused uint64_t tag,
NSString *name,
NSDictionary *args
) {
CHECK(0);
static int eventID = 0;
RCTProfileLock(
RCTProfileOngoingEvents[@(eventID)] = @[
RCTProfileTimestamp(CACurrentMediaTime()),
name,
RCTNullIfNil(args),
];
);
return eventID++;
}
void RCTProfileEndAsyncEvent(
__unused uint64_t tag,
NSString *category,
int cookie,
__unused NSString *name,
NSDictionary *args
) {
CHECK();
RCTProfileLock(
NSArray *event = RCTProfileOngoingEvents[@(cookie)];
if (event) {
NSNumber *endTimestamp = RCTProfileTimestamp(CACurrentMediaTime());
RCTProfileAddEvent(RCTProfileTraceEvents,
@"name": name,
@"cat": categories,
@"name": event[1],
@"cat": category,
@"ph": @"X",
@"ts": startTimestamp,
@"dur": @(endTimestamp.doubleValue - startTimestamp.doubleValue),
@"args": args ?: @[],
@"ts": event[0],
@"dur": @(endTimestamp.doubleValue - [event[0] doubleValue]),
@"args": RCTProfileMergeArgs(event[2], args),
);
[RCTProfileOngoingEvents removeObjectForKey:eventID];
[RCTProfileOngoingEvents removeObjectForKey:@(cookie)];
}
);
}
void RCTProfileImmediateEvent(NSString *name, NSTimeInterval timestamp, NSString *scope)
{
void RCTProfileImmediateEvent(
__unused uint64_t tag,
NSString *name,
char scope
) {
CHECK();
RCTProfileLock(
RCTProfileAddEvent(RCTProfileTraceEvents,
@"name": name,
@"ts": RCTProfileTimestamp(timestamp),
@"scope": scope,
@"ts": RCTProfileTimestamp(CACurrentMediaTime()),
@"scope": @(scope),
@"ph": @"i",
@"args": RCTProfileGetMemoryUsage(),
);

View File

@ -136,18 +136,10 @@ static JSValueRef RCTNoop(JSContextRef context, __unused JSObjectRef object, __u
#if RCT_DEV
static NSMutableArray *profiles;
static JSValueRef RCTConsoleProfile(JSContextRef context, __unused JSObjectRef object, __unused JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], __unused JSValueRef *exception)
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
profiles = [NSMutableArray new];
});
static int profileCounter = 1;
NSString *profileName;
NSNumber *profileID = _RCTProfileBeginEvent();
if (argumentCount > 0) {
profileName = RCTJSValueToNSString(context, arguments[0]);
@ -160,25 +152,14 @@ static JSValueRef RCTConsoleProfile(JSContextRef context, __unused JSObjectRef o
profileInfo = @[RCTJSValueToNSString(context, arguments[1])];
}
[profiles addObjectsFromArray:@[profileName, profileID, profileInfo]];
RCTProfileBeginEvent(0, profileName, profileInfo);
return JSValueMakeUndefined(context);
}
static JSValueRef RCTConsoleProfileEnd(JSContextRef context, __unused JSObjectRef object, __unused JSObjectRef thisObject, __unused size_t argumentCount, __unused const JSValueRef arguments[], __unused JSValueRef *exception)
{
NSString *profileInfo = [profiles lastObject];
[profiles removeLastObject];
NSNumber *profileID = [profiles lastObject];
[profiles removeLastObject];
NSString *profileName = [profiles lastObject];
[profiles removeLastObject];
if (argumentCount > 0 && !JSValueIsUndefined(context, arguments[0])) {
profileName = RCTJSValueToNSString(context, arguments[0]);
}
_RCTProfileEndEvent(profileID, profileName, @"console", profileInfo);
RCTProfileEndEvent(0, @"console", nil);
return JSValueMakeUndefined(context);
}
@ -461,7 +442,7 @@ static NSError *RCTNSErrorFromJSError(JSContextRef context, JSValueRef jsError)
}
onComplete(objcValue, nil);
}), @"js_call", (@{@"module":name, @"method": method, @"args": arguments}))];
}), 0, @"js_call", (@{@"module":name, @"method": method, @"args": arguments}))];
}
- (void)executeApplicationScript:(NSString *)script
@ -493,7 +474,7 @@ static NSError *RCTNSErrorFromJSError(JSContextRef context, JSValueRef jsError)
}
onComplete(error);
}
}), @"js_call", (@{ @"url": sourceURL.absoluteString }))];
}), 0, @"js_call", (@{ @"url": sourceURL.absoluteString }))];
}
- (void)executeBlockOnJavaScriptQueue:(dispatch_block_t)block
@ -555,7 +536,7 @@ static NSError *RCTNSErrorFromJSError(JSContextRef context, JSValueRef jsError)
if (onComplete) {
onComplete(nil);
}
}), @"js_call,json_call", (@{@"objectName": objectName}))];
}), 0, @"js_call,json_call", (@{@"objectName": objectName}))];
}
RCT_EXPORT_METHOD(setContextName:(nonnull NSString *)name)

View File

@ -825,7 +825,7 @@ RCT_EXPORT_METHOD(findSubviewIn:(nonnull NSNumber *)reactTag atPoint:(CGPoint)po
- (void)batchDidComplete
{
RCTProfileBeginEvent();
RCTProfileBeginEvent(0, @"[RCTUIManager batchDidComplete]", nil);
// Gather blocks to be executed now that all view hierarchy manipulations have
// been completed (note that these may still take place before layout has finished)
@ -857,7 +857,7 @@ RCT_EXPORT_METHOD(findSubviewIn:(nonnull NSNumber *)reactTag atPoint:(CGPoint)po
_nextLayoutAnimation = nil;
}
RCTProfileEndEvent(@"[RCTUIManager batchDidComplete]", @"uimanager", @{
RCTProfileEndEvent(0, @"uimanager", @{
@"view_count": @([_viewRegistry count]),
});
[self flushUIBlocks];
@ -877,7 +877,7 @@ RCT_EXPORT_METHOD(findSubviewIn:(nonnull NSNumber *)reactTag atPoint:(CGPoint)po
RCTProfileBeginFlowEvent();
dispatch_async(dispatch_get_main_queue(), ^{
RCTProfileEndFlowEvent();
RCTProfileBeginEvent();
RCTProfileBeginEvent(0, @"UIManager flushUIBlocks", nil);
@try {
for (dispatch_block_t block in previousPendingUIBlocks) {
block();
@ -886,7 +886,7 @@ RCT_EXPORT_METHOD(findSubviewIn:(nonnull NSNumber *)reactTag atPoint:(CGPoint)po
@catch (NSException *exception) {
RCTLogError(@"Exception thrown while executing UI block: %@", exception);
}
RCTProfileEndEvent(@"UIManager flushUIBlocks", @"objc_call", @{
RCTProfileEndEvent(0, @"objc_call", @{
@"count": @(previousPendingUIBlocks.count),
});
});