From 86dc92d5abdb766a778dce68ff5d24e753fe880f Mon Sep 17 00:00:00 2001 From: Tadeu Zagallo Date: Mon, 15 Jun 2015 13:05:05 -0700 Subject: [PATCH] [ReactNative] Add ReactPerf info to profiler timeline Summary: @public Hook into ReactPerf to add markers to `RCTProfile` timeline. Test Plan: {F22569628} --- .../InitializeJavaScriptAppEngine.js | 1 + Libraries/Utilities/BridgeProfiling.js | 25 +++++++++++++++--- React/Base/RCTProfile.m | 26 +++++++++++-------- React/Executors/RCTContextExecutor.m | 4 +++ 4 files changed, 42 insertions(+), 14 deletions(-) diff --git a/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js b/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js index e87f44fca..2896b01ab 100644 --- a/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js +++ b/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js @@ -123,6 +123,7 @@ function setUpWebSockets() { function setupProfile() { console.profile = console.profile || GLOBAL.consoleProfile || function () {}; console.profileEnd = console.profileEnd || GLOBAL.consoleProfileEnd || function () {}; + require('BridgeProfiling').swizzleReactPerf(); } setUpRedBoxErrorHandler(); diff --git a/Libraries/Utilities/BridgeProfiling.js b/Libraries/Utilities/BridgeProfiling.js index c94d84fdd..02685e01c 100644 --- a/Libraries/Utilities/BridgeProfiling.js +++ b/Libraries/Utilities/BridgeProfiling.js @@ -14,7 +14,7 @@ var GLOBAL = GLOBAL || this; var BridgeProfiling = { - profile(profileName: string, args?: any) { + profile(profileName?: string, args?: any) { if (GLOBAL.__BridgeProfilingIsProfiling) { if (args) { try { @@ -27,11 +27,30 @@ var BridgeProfiling = { } }, - profileEnd() { + profileEnd(profileName?: string) { if (GLOBAL.__BridgeProfilingIsProfiling) { - console.profileEnd(); + console.profileEnd(profileName); } }, + + swizzleReactPerf() { + var ReactPerf = require('ReactPerf'); + var originalMeasure = ReactPerf.measure; + 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})`); + } + return ret; + }; + }; + }, }; module.exports = BridgeProfiling; diff --git a/React/Base/RCTProfile.m b/React/Base/RCTProfile.m index f03dc9571..a2b3d7106 100644 --- a/React/Base/RCTProfile.m +++ b/React/Base/RCTProfile.m @@ -43,7 +43,7 @@ NSDictionary *RCTProfileInfo; NSUInteger RCTProfileEventID = 0; NSMutableDictionary *RCTProfileOngoingEvents; NSTimeInterval RCTProfileStartTime; -NSLock *_RCTProfileLock; +NSRecursiveLock *_RCTProfileLock; #pragma mark - Macros @@ -123,15 +123,17 @@ static void RCTProfileForwardInvocation(NSObject *self, __unused SEL cmd, NSInvo NSString *name = [NSString stringWithFormat:@"-[%@ %@]", NSStringFromClass([self class]), NSStringFromSelector(invocation.selector)]; SEL newSel = RCTProfileProxySelector(invocation.selector); - if ([object_getClass(self) instancesRespondToSelector:newSel]) { - invocation.selector = newSel; - RCTProfileBeginEvent(); - [invocation invoke]; - RCTProfileEndEvent(name, @"objc_call,modules,auto", nil); - } else { - // Use original selector to don't change error message - [self doesNotRecognizeSelector:invocation.selector]; - } + RCTProfileLock( + if ([object_getClass(self) instancesRespondToSelector:newSel]) { + invocation.selector = newSel; + RCTProfileBeginEvent(); + [invocation invoke]; + RCTProfileEndEvent(name, @"objc_call,modules,auto", nil); + } else { + // Use original selector to don't change error message + [self doesNotRecognizeSelector:invocation.selector]; + } + ); } static IMP RCTProfileMsgForward(NSObject *, SEL); @@ -191,11 +193,13 @@ void RCTProfileUnhookModules(RCTBridge *bridge) { for (id module in bridge.modules.allValues) { [bridge dispatchBlock:^{ + RCTProfileLock( Class proxyClass = object_getClass(module); if (module.class != proxyClass) { object_setClass(module, module.class); objc_disposeClassPair(proxyClass); } + ); } forModule:module]; }; } @@ -217,7 +221,7 @@ void RCTProfileInit(RCTBridge *bridge) static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ - _RCTProfileLock = [[NSLock alloc] init]; + _RCTProfileLock = [[NSRecursiveLock alloc] init]; }); RCTProfileLock( RCTProfileStartTime = CACurrentMediaTime(); diff --git a/React/Executors/RCTContextExecutor.m b/React/Executors/RCTContextExecutor.m index cf178e553..270bc4a93 100644 --- a/React/Executors/RCTContextExecutor.m +++ b/React/Executors/RCTContextExecutor.m @@ -156,6 +156,10 @@ static JSValueRef RCTConsoleProfileEnd(JSContextRef context, __unused JSObjectRe NSString *profileName = [profiles lastObject]; [profiles removeLastObject]; + if (argumentCount > 0 && !JSValueIsUndefined(context, arguments[0])) { + profileName = RCTJSValueToNSString(context, arguments[0]); + } + _RCTProfileEndEvent(profileID, profileName, @"console", profileInfo); return JSValueMakeUndefined(context);