[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
|
||||
{
|
||||
_socket.delegate = nil;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]) {
|
||||
|
|
Loading…
Reference in New Issue