[ReactNative] Move VSync bound events to JS thread

This commit is contained in:
Tadeu Zagallo 2015-04-22 07:03:55 -07:00
parent 462224727a
commit 3595b79ec3
5 changed files with 91 additions and 50 deletions

View File

@ -175,6 +175,11 @@ typedef void (^WSMessageCallback)(NSError *error, NSDictionary *reply);
});
}
- (void)executeBlockOnJavaScriptQueue:(dispatch_block_t)block
{
dispatch_async(dispatch_get_main_queue(), block);
}
- (void)invalidate
{
_socket.delegate = nil;

View File

@ -694,7 +694,7 @@ static NSDictionary *RCTLocalModulesConfig()
@interface RCTDisplayLink : NSObject <RCTInvalidating>
- (instancetype)initWithBridge:(RCTBridge *)bridge NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithBridge:(RCTBridge *)bridge selector:(SEL)selector NS_DESIGNATED_INITIALIZER;
@end
@ -708,14 +708,16 @@ static NSDictionary *RCTLocalModulesConfig()
{
__weak RCTBridge *_bridge;
CADisplayLink *_displayLink;
SEL _selector;
}
- (instancetype)initWithBridge:(RCTBridge *)bridge
- (instancetype)initWithBridge:(RCTBridge *)bridge selector:(SEL)selector
{
if ((self = [super init])) {
_bridge = bridge;
_selector = selector;
_displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(_update:)];
[_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
[_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
}
return self;
}
@ -735,7 +737,10 @@ static NSDictionary *RCTLocalModulesConfig()
- (void)_update:(CADisplayLink *)displayLink
{
[_bridge _update:displayLink];
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[_bridge performSelector:_selector withObject:displayLink];
#pragma clang diagnostic pop
}
@end
@ -770,6 +775,7 @@ static NSDictionary *RCTLocalModulesConfig()
NSURL *_bundleURL;
RCTBridgeModuleProviderBlock _moduleProvider;
RCTDisplayLink *_displayLink;
RCTDisplayLink *_vsyncDisplayLink;
NSMutableSet *_frameUpdateObservers;
NSMutableArray *_scheduledCalls;
RCTSparseArray *_scheduledCallbacks;
@ -799,11 +805,15 @@ static id<RCTJavaScriptExecutor> _latestJSExecutor;
_latestJSExecutor = _javaScriptExecutor;
_eventDispatcher = [[RCTEventDispatcher alloc] initWithBridge:self];
_methodQueue = dispatch_queue_create("com.facebook.React.BridgeMethodQueue", DISPATCH_QUEUE_SERIAL);
_displayLink = [[RCTDisplayLink alloc] initWithBridge:self];
_frameUpdateObservers = [[NSMutableSet alloc] init];
_scheduledCalls = [[NSMutableArray alloc] init];
_scheduledCallbacks = [[RCTSparseArray alloc] init];
[_javaScriptExecutor executeBlockOnJavaScriptQueue:^{
_displayLink = [[RCTDisplayLink alloc] initWithBridge:self selector:@selector(_jsThreadUpdate:)];
}];
_vsyncDisplayLink = [[RCTDisplayLink alloc] initWithBridge:self selector:@selector(_mainThreadUpdate:)];
// Register passed-in module instances
NSMutableDictionary *preregisteredModules = [[NSMutableDictionary alloc] init];
for (id<RCTBridgeModule> module in _moduleProvider ? _moduleProvider() : nil) {
@ -1008,6 +1018,7 @@ static id<RCTJavaScriptExecutor> _latestJSExecutor;
_javaScriptExecutor = nil;
[_displayLink invalidate];
[_vsyncDisplayLink invalidate];
_frameUpdateObservers = nil;
// Invalidate modules
@ -1294,9 +1305,9 @@ static id<RCTJavaScriptExecutor> _latestJSExecutor;
return YES;
}
- (void)_update:(CADisplayLink *)displayLink
- (void)_jsThreadUpdate:(CADisplayLink *)displayLink
{
RCTProfileImmediateEvent(@"VSYNC", displayLink.timestamp, @"g");
RCTProfileImmediateEvent(@"JS Thread Tick", displayLink.timestamp, @"g");
RCTProfileBeginEvent();
RCTFrameUpdate *frameUpdate = [[RCTFrameUpdate alloc] initWithDisplayLink:displayLink];
@ -1306,13 +1317,6 @@ static id<RCTJavaScriptExecutor> _latestJSExecutor;
}
}
[self _runScheduledCalls];
RCTProfileEndEvent(@"DispatchFrameUpdate", @"objc_call", nil);
}
- (void)_runScheduledCalls
{
#if BATCHED_BRIDGE
NSArray *calls = [_scheduledCallbacks.allObjects arrayByAddingObjectsFromArray:_scheduledCalls];
@ -1330,6 +1334,13 @@ static id<RCTJavaScriptExecutor> _latestJSExecutor;
}
#endif
RCTProfileEndEvent(@"DispatchFrameUpdate", @"objc_call", nil);
}
- (void)_mainThreadUpdate:(CADisplayLink *)displayLink
{
RCTProfileImmediateEvent(@"VSYNC", displayLink.timestamp, @"g");
}
- (void)addFrameUpdateObserver:(id<RCTFrameUpdateObserver>)observer

View File

@ -42,6 +42,13 @@ typedef void (^RCTJavaScriptCallback)(id json, NSError *error);
- (void)injectJSONText:(NSString *)script
asGlobalObjectNamed:(NSString *)objectName
callback:(RCTJavaScriptCompleteBlock)onComplete;
/**
* Enqueue a block to run in the executors JS thread. Fallback to `dispatch_async`
* on the main queue if the executor doesn't own a thread.
*/
- (void)executeBlockOnJavaScriptQueue:(dispatch_block_t)block;
@end
static const char *RCTJavaScriptExecutorID = "RCTJavaScriptExecutorID";

View File

@ -36,6 +36,7 @@ NSDictionary *RCTProfileInfo;
NSUInteger RCTProfileEventID = 0;
NSMutableDictionary *RCTProfileOngoingEvents;
NSTimeInterval RCTProfileStartTime;
NSLock *_RCTProfileLock;
#pragma mark - Macros
@ -51,6 +52,11 @@ if (!RCTProfileIsProfiling()) { \
return __VA_ARGS__; \
}
#define RCTProfileLock(...) \
[_RCTProfileLock lock]; \
__VA_ARGS__ \
[_RCTProfileLock unlock]
#pragma mark - Private Helpers
NSNumber *RCTProfileTimestamp(NSTimeInterval timestamp)
@ -66,7 +72,6 @@ NSString *RCTProfileMemory(vm_size_t memory)
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(),
@ -88,44 +93,55 @@ NSDictionary *RCTProfileGetMemoryUsage(void)
BOOL RCTProfileIsProfiling(void)
{
return RCTProfileInfo != nil;
RCTProfileLock(
BOOL profiling = RCTProfileInfo != nil;
);
return profiling;
}
void RCTProfileInit(void)
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_RCTProfileLock = [[NSLock alloc] init];
});
RCTProfileLock(
RCTProfileStartTime = CACurrentMediaTime();
RCTProfileOngoingEvents = [[NSMutableDictionary alloc] init];
RCTProfileInfo = @{
RCTProfileTraceEvents: [[NSMutableArray alloc] init],
RCTProfileSamples: [[NSMutableArray alloc] init],
};
);
}
NSString *RCTProfileEnd(void)
{
RCTProfileLock(
NSString *log = RCTJSONStringify(RCTProfileInfo, NULL);
RCTProfileEventID = 0;
RCTProfileInfo = nil;
RCTProfileOngoingEvents = nil;
);
return log;
}
NSNumber *_RCTProfileBeginEvent(void)
{
CHECK(@0);
RCTProfileLock(
NSNumber *eventID = @(++RCTProfileEventID);
RCTProfileOngoingEvents[eventID] = RCTProfileTimestamp(CACurrentMediaTime());
);
return eventID;
}
void _RCTProfileEndEvent(NSNumber *eventID, NSString *name, NSString *categories, id args)
{
CHECK();
RCTProfileLock(
NSNumber *startTimestamp = RCTProfileOngoingEvents[eventID];
if (!startTimestamp) {
return;
}
if (startTimestamp) {
NSNumber *endTimestamp = RCTProfileTimestamp(CACurrentMediaTime());
RCTProfileAddEvent(RCTProfileTraceEvents,
@ -138,10 +154,13 @@ void _RCTProfileEndEvent(NSNumber *eventID, NSString *name, NSString *categories
);
[RCTProfileOngoingEvents removeObjectForKey:eventID];
}
);
}
void RCTProfileImmediateEvent(NSString *name, NSTimeInterval timestamp, NSString *scope)
{
CHECK();
RCTProfileLock(
RCTProfileAddEvent(RCTProfileTraceEvents,
@"name": name,
@"ts": RCTProfileTimestamp(timestamp),
@ -149,6 +168,7 @@ void RCTProfileImmediateEvent(NSString *name, NSTimeInterval timestamp, NSString
@"ph": @"i",
@"args": RCTProfileGetMemoryUsage(),
);
);
}
#endif

View File

@ -142,8 +142,6 @@ RCT_IMPORT_METHOD(RCTJSTimers, callTimers)
- (void)didUpdateFrame:(RCTFrameUpdate *)update
{
RCTAssertMainThread();
NSMutableArray *timersToCall = [[NSMutableArray alloc] init];
for (RCTTimer *timer in _timers.allObjects) {
if ([timer updateFoundNeedsJSUpdate]) {