mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-23 14:45:21 +00:00
Measure performance for ASCellNode layout (#2209)
* Measure performance for ASCellNode layout * Address Adlai and Levi's feedback: * Move to ASDisplayNode level * Lock around setting/getting measurement options and results * Record all measurement passes and report times as an array * Only add relevant entries to the performanceMetrics dictionary * Rebase * Store sum and count instead of array * Rename ScopeTimerDataPoint to ScopeTimerSum * Address Levi's feedback * Address Adlai's feedback
This commit is contained in:
committed by
Adlai Holler
parent
8c2f3f666f
commit
59fbfb682d
@@ -18,6 +18,22 @@ void ASPerformBlockOnMainThread(void (^block)());
|
|||||||
void ASPerformBlockOnBackgroundThread(void (^block)()); // DISPATCH_QUEUE_PRIORITY_DEFAULT
|
void ASPerformBlockOnBackgroundThread(void (^block)()); // DISPATCH_QUEUE_PRIORITY_DEFAULT
|
||||||
ASDISPLAYNODE_EXTERN_C_END
|
ASDISPLAYNODE_EXTERN_C_END
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bitmask to indicate what performance measurements the cell should record.
|
||||||
|
*/
|
||||||
|
typedef NS_OPTIONS(NSUInteger, ASDisplayNodePerformanceMeasurementOptions) {
|
||||||
|
ASDisplayNodePerformanceMeasurementOptionLayoutSpec = 1 << 0,
|
||||||
|
ASDisplayNodePerformanceMeasurementOptionLayoutGeneration = 1 << 1
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keys to retrieve performance entries from the performance dictionary.
|
||||||
|
*/
|
||||||
|
extern NSString *const ASDisplayNodeLayoutSpecTotalTimeKey;
|
||||||
|
extern NSString *const ASDisplayNodeLayoutSpecNumberOfPassesKey;
|
||||||
|
extern NSString *const ASDisplayNodeLayoutGenerationTotalTimeKey;
|
||||||
|
extern NSString *const ASDisplayNodeLayoutGenerationNumberOfPassesKey;
|
||||||
|
|
||||||
@interface ASDisplayNode (Beta)
|
@interface ASDisplayNode (Beta)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -57,6 +73,17 @@ ASDISPLAYNODE_EXTERN_C_END
|
|||||||
*/
|
*/
|
||||||
@property (nonatomic, copy, nullable) ASDisplayNodeContextModifier didDisplayNodeContentWithRenderingContext;
|
@property (nonatomic, copy, nullable) ASDisplayNodeContextModifier didDisplayNodeContentWithRenderingContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @abstract A bitmask representing which actions (layout spec, layout generation) should be measured.
|
||||||
|
*/
|
||||||
|
@property (nonatomic, assign) ASDisplayNodePerformanceMeasurementOptions measurementOptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @abstract A dictionary representing performance measurements collected.
|
||||||
|
* @note see the constants above to retrieve relevant performance measurements
|
||||||
|
*/
|
||||||
|
@property (nonatomic, strong, readonly) NSDictionary *performanceMeasurements;
|
||||||
|
|
||||||
/** @name Layout Transitioning */
|
/** @name Layout Transitioning */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -38,6 +38,11 @@
|
|||||||
NSInteger const ASDefaultDrawingPriority = ASDefaultTransactionPriority;
|
NSInteger const ASDefaultDrawingPriority = ASDefaultTransactionPriority;
|
||||||
NSString * const ASRenderingEngineDidDisplayScheduledNodesNotification = @"ASRenderingEngineDidDisplayScheduledNodes";
|
NSString * const ASRenderingEngineDidDisplayScheduledNodesNotification = @"ASRenderingEngineDidDisplayScheduledNodes";
|
||||||
NSString * const ASRenderingEngineDidDisplayNodesScheduledBeforeTimestamp = @"ASRenderingEngineDidDisplayNodesScheduledBeforeTimestamp";
|
NSString * const ASRenderingEngineDidDisplayNodesScheduledBeforeTimestamp = @"ASRenderingEngineDidDisplayNodesScheduledBeforeTimestamp";
|
||||||
|
NSString * const ASDisplayNodeLayoutSpecTotalTimeKey = @"ASDisplayNodeLayoutSpecTotalTime";
|
||||||
|
NSString * const ASDisplayNodeLayoutSpecNumberOfPassesKey = @"ASDisplayNodeLayoutSpecNumberOfPasses";
|
||||||
|
NSString * const ASDisplayNodeLayoutGenerationTotalTimeKey = @"ASDisplayNodeLayoutGenerationTotalTime";
|
||||||
|
NSString * const ASDisplayNodeLayoutGenerationNumberOfPassesKey = @"ASDisplayNodeLayoutGenerationNumberOfPasses";
|
||||||
|
|
||||||
|
|
||||||
// Forward declare CALayerDelegate protocol as the iOS 10 SDK moves CALayerDelegate from a formal delegate to a protocol.
|
// Forward declare CALayerDelegate protocol as the iOS 10 SDK moves CALayerDelegate from a formal delegate to a protocol.
|
||||||
// We have to forward declare the protocol as this place otherwise it will not compile compiling with an Base SDK < iOS 10
|
// We have to forward declare the protocol as this place otherwise it will not compile compiling with an Base SDK < iOS 10
|
||||||
@@ -1156,6 +1161,33 @@ ASLayoutableSizeHelperForwarding
|
|||||||
// subclass override
|
// subclass override
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setMeasurementOptions:(ASDisplayNodePerformanceMeasurementOptions)measurementOptions
|
||||||
|
{
|
||||||
|
ASDN::MutexLocker l(__instanceLock__);
|
||||||
|
_measurementOptions = measurementOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (ASDisplayNodePerformanceMeasurementOptions)measurementOptions
|
||||||
|
{
|
||||||
|
ASDN::MutexLocker l(__instanceLock__);
|
||||||
|
return _measurementOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSDictionary *)performanceMeasurements
|
||||||
|
{
|
||||||
|
ASDN::MutexLocker l(__instanceLock__);
|
||||||
|
NSMutableDictionary *measurements = [NSMutableDictionary dictionaryWithCapacity:4];
|
||||||
|
if (_measurementOptions & ASDisplayNodePerformanceMeasurementOptionLayoutSpec) {
|
||||||
|
measurements[ASDisplayNodeLayoutSpecTotalTimeKey] = @(_layoutSpecTotalTime);
|
||||||
|
measurements[ASDisplayNodeLayoutSpecNumberOfPassesKey] = @(_layoutSpecNumberOfPasses);
|
||||||
|
}
|
||||||
|
if (_measurementOptions & ASDisplayNodePerformanceMeasurementOptionLayoutGeneration) {
|
||||||
|
measurements[ASDisplayNodeLayoutGenerationTotalTimeKey] = @(_layoutGenerationTotalTime);
|
||||||
|
measurements[ASDisplayNodeLayoutGenerationNumberOfPassesKey] = @(_layoutGenerationNumberOfPasses);
|
||||||
|
}
|
||||||
|
return measurements;
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark - Asynchronous display
|
#pragma mark - Asynchronous display
|
||||||
|
|
||||||
- (BOOL)displaysAsynchronously
|
- (BOOL)displaysAsynchronously
|
||||||
@@ -2343,7 +2375,15 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
|
|||||||
|
|
||||||
ASDN::MutexLocker l(__instanceLock__);
|
ASDN::MutexLocker l(__instanceLock__);
|
||||||
if ((_methodOverrides & ASDisplayNodeMethodOverrideLayoutSpecThatFits) || _layoutSpecBlock != NULL) {
|
if ((_methodOverrides & ASDisplayNodeMethodOverrideLayoutSpecThatFits) || _layoutSpecBlock != NULL) {
|
||||||
ASLayoutSpec *layoutSpec = [self layoutSpecThatFits:constrainedSize];
|
ASLayoutSpec *layoutSpec = nil;
|
||||||
|
// optional performance measurement for cell nodes
|
||||||
|
if (_measurementOptions & ASDisplayNodePerformanceMeasurementOptionLayoutSpec) {
|
||||||
|
ASDN::SumScopeTimer t(_layoutSpecTotalTime);
|
||||||
|
_layoutSpecNumberOfPasses++;
|
||||||
|
layoutSpec = [self layoutSpecThatFits:constrainedSize];
|
||||||
|
} else {
|
||||||
|
layoutSpec = [self layoutSpecThatFits:constrainedSize];
|
||||||
|
}
|
||||||
|
|
||||||
ASDisplayNodeAssert(layoutSpec.isMutable, @"Node %@ returned layout spec %@ that has already been used. Layout specs should always be regenerated.", self, layoutSpec);
|
ASDisplayNodeAssert(layoutSpec.isMutable, @"Node %@ returned layout spec %@ that has already been used. Layout specs should always be regenerated.", self, layoutSpec);
|
||||||
|
|
||||||
@@ -2353,7 +2393,16 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
|
|||||||
ASEnvironmentStatePropagateDown(layoutSpec, self.environmentTraitCollection);
|
ASEnvironmentStatePropagateDown(layoutSpec, self.environmentTraitCollection);
|
||||||
|
|
||||||
layoutSpec.isMutable = NO;
|
layoutSpec.isMutable = NO;
|
||||||
ASLayout *layout = [layoutSpec layoutThatFits:constrainedSize];
|
ASLayout *layout = nil;
|
||||||
|
// optional performance measurement for cell nodes
|
||||||
|
if (_measurementOptions & ASDisplayNodePerformanceMeasurementOptionLayoutGeneration) {
|
||||||
|
ASDN::SumScopeTimer t(_layoutGenerationTotalTime);
|
||||||
|
_layoutGenerationNumberOfPasses++;
|
||||||
|
layout = [layoutSpec layoutThatFits:constrainedSize];
|
||||||
|
} else {
|
||||||
|
layout = [layoutSpec layoutThatFits:constrainedSize];
|
||||||
|
}
|
||||||
|
|
||||||
ASDisplayNodeAssertNotNil(layout, @"[ASLayoutSpec measureWithSizeRange:] should never return nil! %@, %@", self, layoutSpec);
|
ASDisplayNodeAssertNotNil(layout, @"[ASLayoutSpec measureWithSizeRange:] should never return nil! %@, %@", self, layoutSpec);
|
||||||
|
|
||||||
// Make sure layoutableObject of the root layout is `self`, so that the flattened layout will be structurally correct.
|
// Make sure layoutableObject of the root layout is `self`, so that the flattened layout will be structurally correct.
|
||||||
|
|||||||
@@ -22,6 +22,8 @@
|
|||||||
#import "ASEnvironment.h"
|
#import "ASEnvironment.h"
|
||||||
#import "ASObjectDescriptionHelpers.h"
|
#import "ASObjectDescriptionHelpers.h"
|
||||||
|
|
||||||
|
#import "ASDisplayNode+Beta.h"
|
||||||
|
|
||||||
@protocol _ASDisplayLayerDelegate;
|
@protocol _ASDisplayLayerDelegate;
|
||||||
@class _ASDisplayLayer;
|
@class _ASDisplayLayer;
|
||||||
@class _ASPendingState;
|
@class _ASPendingState;
|
||||||
@@ -163,6 +165,13 @@ FOUNDATION_EXPORT NSString * const ASRenderingEngineDidDisplayNodesScheduledBefo
|
|||||||
CGPoint _accessibilityActivationPoint;
|
CGPoint _accessibilityActivationPoint;
|
||||||
UIBezierPath *_accessibilityPath;
|
UIBezierPath *_accessibilityPath;
|
||||||
|
|
||||||
|
// performance measurement
|
||||||
|
ASDisplayNodePerformanceMeasurementOptions _measurementOptions;
|
||||||
|
NSTimeInterval _layoutSpecTotalTime;
|
||||||
|
NSUInteger _layoutSpecNumberOfPasses;
|
||||||
|
NSTimeInterval _layoutGenerationTotalTime;
|
||||||
|
NSUInteger _layoutGenerationNumberOfPasses;
|
||||||
|
|
||||||
#if TIME_DISPLAYNODE_OPS
|
#if TIME_DISPLAYNODE_OPS
|
||||||
@public
|
@public
|
||||||
NSTimeInterval _debugTimeToCreateView;
|
NSTimeInterval _debugTimeToCreateView;
|
||||||
|
|||||||
@@ -37,4 +37,16 @@ namespace ASDN {
|
|||||||
outT = CACurrentMediaTime() - begin;
|
outT = CACurrentMediaTime() - begin;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// variant where repeated calls are summed
|
||||||
|
struct SumScopeTimer {
|
||||||
|
NSTimeInterval begin;
|
||||||
|
NSTimeInterval &outT;
|
||||||
|
SumScopeTimer(NSTimeInterval &outRef) : outT(outRef) {
|
||||||
|
begin = CACurrentMediaTime();
|
||||||
|
}
|
||||||
|
~SumScopeTimer() {
|
||||||
|
outT += CACurrentMediaTime() - begin;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user