[ReactNative] Move VSync bound events to JS thread
This commit is contained in:
parent
462224727a
commit
3595b79ec3
|
@ -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
|
- (void)invalidate
|
||||||
{
|
{
|
||||||
_socket.delegate = nil;
|
_socket.delegate = nil;
|
||||||
|
|
|
@ -694,7 +694,7 @@ static NSDictionary *RCTLocalModulesConfig()
|
||||||
|
|
||||||
@interface RCTDisplayLink : NSObject <RCTInvalidating>
|
@interface RCTDisplayLink : NSObject <RCTInvalidating>
|
||||||
|
|
||||||
- (instancetype)initWithBridge:(RCTBridge *)bridge NS_DESIGNATED_INITIALIZER;
|
- (instancetype)initWithBridge:(RCTBridge *)bridge selector:(SEL)selector NS_DESIGNATED_INITIALIZER;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@ -708,14 +708,16 @@ static NSDictionary *RCTLocalModulesConfig()
|
||||||
{
|
{
|
||||||
__weak RCTBridge *_bridge;
|
__weak RCTBridge *_bridge;
|
||||||
CADisplayLink *_displayLink;
|
CADisplayLink *_displayLink;
|
||||||
|
SEL _selector;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype)initWithBridge:(RCTBridge *)bridge
|
- (instancetype)initWithBridge:(RCTBridge *)bridge selector:(SEL)selector
|
||||||
{
|
{
|
||||||
if ((self = [super init])) {
|
if ((self = [super init])) {
|
||||||
_bridge = bridge;
|
_bridge = bridge;
|
||||||
|
_selector = selector;
|
||||||
_displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(_update:)];
|
_displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(_update:)];
|
||||||
[_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
|
[_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
@ -735,7 +737,10 @@ static NSDictionary *RCTLocalModulesConfig()
|
||||||
|
|
||||||
- (void)_update:(CADisplayLink *)displayLink
|
- (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
|
@end
|
||||||
|
@ -770,6 +775,7 @@ static NSDictionary *RCTLocalModulesConfig()
|
||||||
NSURL *_bundleURL;
|
NSURL *_bundleURL;
|
||||||
RCTBridgeModuleProviderBlock _moduleProvider;
|
RCTBridgeModuleProviderBlock _moduleProvider;
|
||||||
RCTDisplayLink *_displayLink;
|
RCTDisplayLink *_displayLink;
|
||||||
|
RCTDisplayLink *_vsyncDisplayLink;
|
||||||
NSMutableSet *_frameUpdateObservers;
|
NSMutableSet *_frameUpdateObservers;
|
||||||
NSMutableArray *_scheduledCalls;
|
NSMutableArray *_scheduledCalls;
|
||||||
RCTSparseArray *_scheduledCallbacks;
|
RCTSparseArray *_scheduledCallbacks;
|
||||||
|
@ -799,11 +805,15 @@ static id<RCTJavaScriptExecutor> _latestJSExecutor;
|
||||||
_latestJSExecutor = _javaScriptExecutor;
|
_latestJSExecutor = _javaScriptExecutor;
|
||||||
_eventDispatcher = [[RCTEventDispatcher alloc] initWithBridge:self];
|
_eventDispatcher = [[RCTEventDispatcher alloc] initWithBridge:self];
|
||||||
_methodQueue = dispatch_queue_create("com.facebook.React.BridgeMethodQueue", DISPATCH_QUEUE_SERIAL);
|
_methodQueue = dispatch_queue_create("com.facebook.React.BridgeMethodQueue", DISPATCH_QUEUE_SERIAL);
|
||||||
_displayLink = [[RCTDisplayLink alloc] initWithBridge:self];
|
|
||||||
_frameUpdateObservers = [[NSMutableSet alloc] init];
|
_frameUpdateObservers = [[NSMutableSet alloc] init];
|
||||||
_scheduledCalls = [[NSMutableArray alloc] init];
|
_scheduledCalls = [[NSMutableArray alloc] init];
|
||||||
_scheduledCallbacks = [[RCTSparseArray 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
|
// Register passed-in module instances
|
||||||
NSMutableDictionary *preregisteredModules = [[NSMutableDictionary alloc] init];
|
NSMutableDictionary *preregisteredModules = [[NSMutableDictionary alloc] init];
|
||||||
for (id<RCTBridgeModule> module in _moduleProvider ? _moduleProvider() : nil) {
|
for (id<RCTBridgeModule> module in _moduleProvider ? _moduleProvider() : nil) {
|
||||||
|
@ -1008,6 +1018,7 @@ static id<RCTJavaScriptExecutor> _latestJSExecutor;
|
||||||
_javaScriptExecutor = nil;
|
_javaScriptExecutor = nil;
|
||||||
|
|
||||||
[_displayLink invalidate];
|
[_displayLink invalidate];
|
||||||
|
[_vsyncDisplayLink invalidate];
|
||||||
_frameUpdateObservers = nil;
|
_frameUpdateObservers = nil;
|
||||||
|
|
||||||
// Invalidate modules
|
// Invalidate modules
|
||||||
|
@ -1294,9 +1305,9 @@ static id<RCTJavaScriptExecutor> _latestJSExecutor;
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_update:(CADisplayLink *)displayLink
|
- (void)_jsThreadUpdate:(CADisplayLink *)displayLink
|
||||||
{
|
{
|
||||||
RCTProfileImmediateEvent(@"VSYNC", displayLink.timestamp, @"g");
|
RCTProfileImmediateEvent(@"JS Thread Tick", displayLink.timestamp, @"g");
|
||||||
RCTProfileBeginEvent();
|
RCTProfileBeginEvent();
|
||||||
|
|
||||||
RCTFrameUpdate *frameUpdate = [[RCTFrameUpdate alloc] initWithDisplayLink:displayLink];
|
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
|
#if BATCHED_BRIDGE
|
||||||
|
|
||||||
NSArray *calls = [_scheduledCallbacks.allObjects arrayByAddingObjectsFromArray:_scheduledCalls];
|
NSArray *calls = [_scheduledCallbacks.allObjects arrayByAddingObjectsFromArray:_scheduledCalls];
|
||||||
|
@ -1330,6 +1334,13 @@ static id<RCTJavaScriptExecutor> _latestJSExecutor;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
RCTProfileEndEvent(@"DispatchFrameUpdate", @"objc_call", nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_mainThreadUpdate:(CADisplayLink *)displayLink
|
||||||
|
{
|
||||||
|
RCTProfileImmediateEvent(@"VSYNC", displayLink.timestamp, @"g");
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)addFrameUpdateObserver:(id<RCTFrameUpdateObserver>)observer
|
- (void)addFrameUpdateObserver:(id<RCTFrameUpdateObserver>)observer
|
||||||
|
|
|
@ -42,6 +42,13 @@ typedef void (^RCTJavaScriptCallback)(id json, NSError *error);
|
||||||
- (void)injectJSONText:(NSString *)script
|
- (void)injectJSONText:(NSString *)script
|
||||||
asGlobalObjectNamed:(NSString *)objectName
|
asGlobalObjectNamed:(NSString *)objectName
|
||||||
callback:(RCTJavaScriptCompleteBlock)onComplete;
|
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
|
@end
|
||||||
|
|
||||||
static const char *RCTJavaScriptExecutorID = "RCTJavaScriptExecutorID";
|
static const char *RCTJavaScriptExecutorID = "RCTJavaScriptExecutorID";
|
||||||
|
|
|
@ -36,6 +36,7 @@ NSDictionary *RCTProfileInfo;
|
||||||
NSUInteger RCTProfileEventID = 0;
|
NSUInteger RCTProfileEventID = 0;
|
||||||
NSMutableDictionary *RCTProfileOngoingEvents;
|
NSMutableDictionary *RCTProfileOngoingEvents;
|
||||||
NSTimeInterval RCTProfileStartTime;
|
NSTimeInterval RCTProfileStartTime;
|
||||||
|
NSLock *_RCTProfileLock;
|
||||||
|
|
||||||
#pragma mark - Macros
|
#pragma mark - Macros
|
||||||
|
|
||||||
|
@ -51,6 +52,11 @@ if (!RCTProfileIsProfiling()) { \
|
||||||
return __VA_ARGS__; \
|
return __VA_ARGS__; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define RCTProfileLock(...) \
|
||||||
|
[_RCTProfileLock lock]; \
|
||||||
|
__VA_ARGS__ \
|
||||||
|
[_RCTProfileLock unlock]
|
||||||
|
|
||||||
#pragma mark - Private Helpers
|
#pragma mark - Private Helpers
|
||||||
|
|
||||||
NSNumber *RCTProfileTimestamp(NSTimeInterval timestamp)
|
NSNumber *RCTProfileTimestamp(NSTimeInterval timestamp)
|
||||||
|
@ -66,7 +72,6 @@ NSString *RCTProfileMemory(vm_size_t memory)
|
||||||
|
|
||||||
NSDictionary *RCTProfileGetMemoryUsage(void)
|
NSDictionary *RCTProfileGetMemoryUsage(void)
|
||||||
{
|
{
|
||||||
CHECK(@{});
|
|
||||||
struct task_basic_info info;
|
struct task_basic_info info;
|
||||||
mach_msg_type_number_t size = sizeof(info);
|
mach_msg_type_number_t size = sizeof(info);
|
||||||
kern_return_t kerr = task_info(mach_task_self(),
|
kern_return_t kerr = task_info(mach_task_self(),
|
||||||
|
@ -88,66 +93,81 @@ NSDictionary *RCTProfileGetMemoryUsage(void)
|
||||||
|
|
||||||
BOOL RCTProfileIsProfiling(void)
|
BOOL RCTProfileIsProfiling(void)
|
||||||
{
|
{
|
||||||
return RCTProfileInfo != nil;
|
RCTProfileLock(
|
||||||
|
BOOL profiling = RCTProfileInfo != nil;
|
||||||
|
);
|
||||||
|
return profiling;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RCTProfileInit(void)
|
void RCTProfileInit(void)
|
||||||
{
|
{
|
||||||
RCTProfileStartTime = CACurrentMediaTime();
|
static dispatch_once_t onceToken;
|
||||||
RCTProfileOngoingEvents = [[NSMutableDictionary alloc] init];
|
dispatch_once(&onceToken, ^{
|
||||||
RCTProfileInfo = @{
|
_RCTProfileLock = [[NSLock alloc] init];
|
||||||
RCTProfileTraceEvents: [[NSMutableArray alloc] init],
|
});
|
||||||
RCTProfileSamples: [[NSMutableArray alloc] init],
|
RCTProfileLock(
|
||||||
};
|
RCTProfileStartTime = CACurrentMediaTime();
|
||||||
|
RCTProfileOngoingEvents = [[NSMutableDictionary alloc] init];
|
||||||
|
RCTProfileInfo = @{
|
||||||
|
RCTProfileTraceEvents: [[NSMutableArray alloc] init],
|
||||||
|
RCTProfileSamples: [[NSMutableArray alloc] init],
|
||||||
|
};
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
NSString *RCTProfileEnd(void)
|
NSString *RCTProfileEnd(void)
|
||||||
{
|
{
|
||||||
NSString *log = RCTJSONStringify(RCTProfileInfo, NULL);
|
RCTProfileLock(
|
||||||
RCTProfileEventID = 0;
|
NSString *log = RCTJSONStringify(RCTProfileInfo, NULL);
|
||||||
RCTProfileInfo = nil;
|
RCTProfileEventID = 0;
|
||||||
RCTProfileOngoingEvents = nil;
|
RCTProfileInfo = nil;
|
||||||
|
RCTProfileOngoingEvents = nil;
|
||||||
|
);
|
||||||
return log;
|
return log;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSNumber *_RCTProfileBeginEvent(void)
|
NSNumber *_RCTProfileBeginEvent(void)
|
||||||
{
|
{
|
||||||
CHECK(@0);
|
CHECK(@0);
|
||||||
NSNumber *eventID = @(++RCTProfileEventID);
|
RCTProfileLock(
|
||||||
RCTProfileOngoingEvents[eventID] = RCTProfileTimestamp(CACurrentMediaTime());
|
NSNumber *eventID = @(++RCTProfileEventID);
|
||||||
|
RCTProfileOngoingEvents[eventID] = RCTProfileTimestamp(CACurrentMediaTime());
|
||||||
|
);
|
||||||
return eventID;
|
return eventID;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _RCTProfileEndEvent(NSNumber *eventID, NSString *name, NSString *categories, id args)
|
void _RCTProfileEndEvent(NSNumber *eventID, NSString *name, NSString *categories, id args)
|
||||||
{
|
{
|
||||||
CHECK();
|
CHECK();
|
||||||
NSNumber *startTimestamp = RCTProfileOngoingEvents[eventID];
|
RCTProfileLock(
|
||||||
if (!startTimestamp) {
|
NSNumber *startTimestamp = RCTProfileOngoingEvents[eventID];
|
||||||
return;
|
if (startTimestamp) {
|
||||||
}
|
NSNumber *endTimestamp = RCTProfileTimestamp(CACurrentMediaTime());
|
||||||
|
|
||||||
NSNumber *endTimestamp = RCTProfileTimestamp(CACurrentMediaTime());
|
RCTProfileAddEvent(RCTProfileTraceEvents,
|
||||||
|
@"name": name,
|
||||||
RCTProfileAddEvent(RCTProfileTraceEvents,
|
@"cat": categories,
|
||||||
@"name": name,
|
@"ph": @"X",
|
||||||
@"cat": categories,
|
@"ts": startTimestamp,
|
||||||
@"ph": @"X",
|
@"dur": @(endTimestamp.doubleValue - startTimestamp.doubleValue),
|
||||||
@"ts": startTimestamp,
|
@"args": args ?: @[],
|
||||||
@"dur": @(endTimestamp.doubleValue - startTimestamp.doubleValue),
|
);
|
||||||
@"args": args ?: @[],
|
[RCTProfileOngoingEvents removeObjectForKey:eventID];
|
||||||
|
}
|
||||||
);
|
);
|
||||||
[RCTProfileOngoingEvents removeObjectForKey:eventID];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RCTProfileImmediateEvent(NSString *name, NSTimeInterval timestamp, NSString *scope)
|
void RCTProfileImmediateEvent(NSString *name, NSTimeInterval timestamp, NSString *scope)
|
||||||
{
|
{
|
||||||
CHECK();
|
CHECK();
|
||||||
RCTProfileAddEvent(RCTProfileTraceEvents,
|
RCTProfileLock(
|
||||||
@"name": name,
|
RCTProfileAddEvent(RCTProfileTraceEvents,
|
||||||
@"ts": RCTProfileTimestamp(timestamp),
|
@"name": name,
|
||||||
@"scope": scope,
|
@"ts": RCTProfileTimestamp(timestamp),
|
||||||
@"ph": @"i",
|
@"scope": scope,
|
||||||
@"args": RCTProfileGetMemoryUsage(),
|
@"ph": @"i",
|
||||||
|
@"args": RCTProfileGetMemoryUsage(),
|
||||||
|
);
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -142,8 +142,6 @@ RCT_IMPORT_METHOD(RCTJSTimers, callTimers)
|
||||||
|
|
||||||
- (void)didUpdateFrame:(RCTFrameUpdate *)update
|
- (void)didUpdateFrame:(RCTFrameUpdate *)update
|
||||||
{
|
{
|
||||||
RCTAssertMainThread();
|
|
||||||
|
|
||||||
NSMutableArray *timersToCall = [[NSMutableArray alloc] init];
|
NSMutableArray *timersToCall = [[NSMutableArray alloc] init];
|
||||||
for (RCTTimer *timer in _timers.allObjects) {
|
for (RCTTimer *timer in _timers.allObjects) {
|
||||||
if ([timer updateFoundNeedsJSUpdate]) {
|
if ([timer updateFoundNeedsJSUpdate]) {
|
||||||
|
|
Loading…
Reference in New Issue