[ASDisplayNode] Add Event Tracing to Help Debugging (#2243)

* Add some simple event logging for ASDisplayNode

Improve the tracing

* Add header to copy files phase

* Make event header public
This commit is contained in:
Adlai Holler
2016-09-15 13:24:19 -07:00
committed by GitHub
parent 8459c1e825
commit 25de53bb13
12 changed files with 315 additions and 27 deletions

View File

@@ -308,6 +308,7 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
- (void)_initializeInstance
{
[self _staticInitialize];
_eventLogHead = -1;
_contentsScaleForDisplay = ASScreenScale();
_displaySentinel = [[ASSentinel alloc] init];
@@ -323,6 +324,7 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
_flags.canClearContentsOfLayer = YES;
_flags.canCallSetNeedsDisplayOfLayer = YES;
ASDisplayNodeLogEvent(self, @"init");
}
- (instancetype)init
@@ -428,7 +430,7 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
{
ASDisplayNodeAssertMainThread();
// Synchronous nodes may not be able to call the hierarchy notifications, so only enforce for regular nodes.
ASDisplayNodeAssert(_flags.synchronous || !ASInterfaceStateIncludesVisible(_interfaceState), @"Node should always be marked invisible before deallocating; interfaceState: %lu, %@", (unsigned long)_interfaceState, self);
ASDisplayNodeAssert(_flags.synchronous || !ASInterfaceStateIncludesVisible(_interfaceState), @"Node should always be marked invisible before deallocating. Node: %@", self);
self.asyncLayer.asyncDelegate = nil;
_view.asyncdisplaykit_node = nil;
@@ -586,6 +588,51 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
}
}
#if ASDISPLAYNODE_EVENTLOG_ENABLE
- (void)_logEventWithBacktrace:(NSArray<NSString *> *)backtrace format:(NSString *)format, ...
{
va_list args;
va_start(args, format);
ASTraceEvent *event = [[ASTraceEvent alloc] initWithObject:self
backtrace:backtrace
format:format
arguments:args];
va_end(args);
ASDN::MutexLocker l(__instanceLock__);
// Create the array if needed.
if (_eventLog == nil) {
_eventLog = [NSMutableArray arrayWithCapacity:ASDISPLAYNODE_EVENTLOG_CAPACITY];
}
// Increment the head index.
_eventLogHead = (_eventLogHead + 1) % ASDISPLAYNODE_EVENTLOG_CAPACITY;
if (_eventLogHead < _eventLog.count) {
[_eventLog replaceObjectAtIndex:_eventLogHead withObject:event];
} else {
[_eventLog insertObject:event atIndex:_eventLogHead];
}
}
- (NSArray<ASTraceEvent *> *)eventLog
{
ASDN::MutexLocker l(__instanceLock__);
NSUInteger tail = (_eventLogHead + 1);
NSUInteger count = _eventLog.count;
NSMutableArray<ASTraceEvent *> *result = [NSMutableArray array];
// Start from `tail` and go through array, wrapping around when we exceed end index.
for (NSUInteger actualIndex = 0; actualIndex < ASDISPLAYNODE_EVENTLOG_CAPACITY; actualIndex++) {
NSInteger ringIndex = (tail + actualIndex) % ASDISPLAYNODE_EVENTLOG_CAPACITY;
if (ringIndex < count) {
[result addObject:_eventLog[ringIndex]];
}
}
return result;
}
#endif
- (UIView *)view
{
ASDisplayNodeAssert(!_flags.layerBacked, @"Call to -view undefined on layer-backed nodes");
@@ -1646,6 +1693,7 @@ static bool disableNotificationsForMovingBetweenParents(ASDisplayNode *from, ASD
_subnodes = [[NSMutableArray alloc] init];
}
ASDisplayNodeLogEvent(self, @"%@ %@", NSStringFromSelector(_cmd), subnode);
[_subnodes addObject:subnode];
// This call will apply our .hierarchyState to the new subnode.
@@ -1701,6 +1749,7 @@ static bool disableNotificationsForMovingBetweenParents(ASDisplayNode *from, ASD
if (!_subnodes)
_subnodes = [[NSMutableArray alloc] init];
ASDisplayNodeLogEvent(self, @"%@: %@", NSStringFromSelector(_cmd), subnode);
[_subnodes insertObject:subnode atIndex:subnodeIndex];
[subnode __setSupernode:self];
@@ -1945,6 +1994,7 @@ static NSInteger incrementIfFound(NSInteger i) {
return;
}
ASDisplayNodeLogEvent(self, @"%@: %@", NSStringFromSelector(_cmd), subnode);
[_subnodes removeObjectIdenticalTo:subnode];
[subnode __setSupernode:nil];
@@ -2157,6 +2207,7 @@ static NSInteger incrementIfFound(NSInteger i) {
}
if (supernodeDidChange) {
ASDisplayNodeLogEvent(self, @"supernodeDidChange: %@, oldValue = %@", ASObjectDescriptionMakeTiny(newSupernode), ASObjectDescriptionMakeTiny(oldSupernode));
// Hierarchy state
ASHierarchyState stateToEnterOrExit = (newSupernode ? newSupernode.hierarchyState
: oldSupernode.hierarchyState);
@@ -2422,11 +2473,13 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
ASLayoutableValidateLayout(layout);
#endif
}
ASDisplayNodeLogEvent(self, @"computedLayout: %@", layout);
return [layout filteredNodeLayoutTree];
} else {
// If neither -layoutSpecThatFits: nor -calculateSizeThatFits: is overridden by subclassses, preferredFrameSize should be used,
// assume that the default implementation of -calculateSizeThatFits: returns it.
CGSize size = [self calculateSizeThatFits:constrainedSize.max];
ASDisplayNodeLogEvent(self, @"calculatedSize: %@", NSStringFromCGSize(size));
return [ASLayout layoutWithLayoutable:self size:ASSizeRangeClamp(constrainedSize, size) sublayouts:nil];
}
}
@@ -2565,6 +2618,7 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
{
ASDN::MutexLocker l(__instanceLock__);
ASDisplayNodeLogEvent(self, @"didLoad");
for (ASDisplayNodeDidLoadBlock block in _onDidLoadBlocks) {
block(self);
}
@@ -2765,8 +2819,10 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
if (nowPreload != wasPreload) {
if (nowPreload) {
ASDisplayNodeLogEvent(self, @"didEnterPreloadState: %@", NSStringFromASInterfaceState(newState));
[self didEnterPreloadState];
} else {
ASDisplayNodeLogEvent(self, @"didExitPreloadState: %@", NSStringFromASInterfaceState(newState));
[self didExitPreloadState];
}
}
@@ -2813,8 +2869,10 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
}
if (nowDisplay) {
ASDisplayNodeLogEvent(self, @"didEnterDisplayState: %@", NSStringFromASInterfaceState(newState));
[self didEnterDisplayState];
} else {
ASDisplayNodeLogEvent(self, @"didExitDisplayState: %@", NSStringFromASInterfaceState(newState));
[self didExitDisplayState];
}
}
@@ -2826,8 +2884,10 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
if (nowVisible != wasVisible) {
if (nowVisible) {
ASDisplayNodeLogEvent(self, @"didEnterVisibleState: %@", NSStringFromASInterfaceState(newState));
[self didEnterVisibleState];
} else {
ASDisplayNodeLogEvent(self, @"didExitVisibleState: %@", NSStringFromASInterfaceState(newState));
[self didExitVisibleState];
}
}
@@ -2855,6 +2915,7 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
if (interfaceState == ASInterfaceStateNone) {
return; // This method is a no-op with a 0-bitfield argument, so don't bother recursing.
}
ASDisplayNodeLogEvent(self, @"%@ %@", NSStringFromSelector(_cmd), NSStringFromASInterfaceState(interfaceState));
ASDisplayNodePerformBlockOnEveryNode(nil, self, ^(ASDisplayNode *node) {
node.interfaceState &= (~interfaceState);
});
@@ -2929,10 +2990,8 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
}
}
}
if (newState != oldState) {
LOG(@"setHierarchyState: oldState = %lu, newState = %lu", (unsigned long)oldState, (unsigned long)newState);
}
ASDisplayNodeLogEvent(self, @"setHierarchyState: oldState = %@, newState = %@", NSStringFromASHierarchyState(oldState), NSStringFromASHierarchyState(newState));
}
- (void)enterHierarchyState:(ASHierarchyState)hierarchyState
@@ -2979,6 +3038,7 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
{
ASDisplayNodeAssertMainThread();
ASDisplayNodeLogEvent(self, @"displayWillStart");
// in case current node takes longer to display than it's subnodes, treat it as a dependent node
[self _pendingNodeWillDisplay:self];
@@ -2989,6 +3049,7 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
{
ASDisplayNodeAssertMainThread();
ASDisplayNodeLogEvent(self, @"displayDidFinish");
[self _pendingNodeDidDisplay:self];
[_supernode subnodeDisplayDidFinish:self];
@@ -3338,15 +3399,15 @@ static const char *ASDisplayNodeDrawingPriorityKey = "ASDrawingPriority";
}
if (self.layerBacked) {
CALayer *rootLayer = self.layer;
CALayer *rootLayer = _layer;
CALayer *nextLayer = rootLayer;
while ((nextLayer = rootLayer.superlayer) != nil) {
rootLayer = nextLayer;
}
return [self.layer convertRect:self.threadSafeBounds toLayer:rootLayer];
return [_layer convertRect:self.threadSafeBounds toLayer:rootLayer];
} else {
return [self.view convertRect:self.threadSafeBounds toView:nil];
return [_view convertRect:self.threadSafeBounds toView:nil];
}
}
@@ -3396,6 +3457,7 @@ static const char *ASDisplayNodeDrawingPriorityKey = "ASDrawingPriority";
{
if (ASEnvironmentTraitCollectionIsEqualToASEnvironmentTraitCollection(environmentTraitCollection, _environmentState.environmentTraitCollection) == NO) {
_environmentState.environmentTraitCollection = environmentTraitCollection;
ASDisplayNodeLogEvent(self, @"asyncTraitCollectionDidChange: %@", NSStringFromASEnvironmentTraitCollection(environmentTraitCollection));
[self asyncTraitCollectionDidChange];
}
}
@@ -3411,7 +3473,7 @@ ASEnvironmentLayoutExtensibilityForwarding
- (void)asyncTraitCollectionDidChange
{
// Subclass override
}
#if TARGET_OS_TV