From f9dbf5af77d6770b34b7e19ee0f61f15d3516e71 Mon Sep 17 00:00:00 2001 From: Hannah Troisi Date: Mon, 12 Jun 2017 21:31:37 -0700 Subject: [PATCH] [Performance] Convert ASLayoutElementSize to atomic #trivial (#331) * [Performance] Convert ASLayoutElementSize to atomic * [ASLayoutElementStyle] Put locks around setter methods. * Also add lock to setSize: internal method. --- Source/Layout/ASLayoutElement.mm | 134 +++++++++++++++++-------------- 1 file changed, 73 insertions(+), 61 deletions(-) diff --git a/Source/Layout/ASLayoutElement.mm b/Source/Layout/ASLayoutElement.mm index 6909821a6..047c62a44 100644 --- a/Source/Layout/ASLayoutElement.mm +++ b/Source/Layout/ASLayoutElement.mm @@ -110,6 +110,13 @@ void ASLayoutElementPopContext() NSString * const ASLayoutElementStyleLayoutPositionProperty = @"ASLayoutElementStyleLayoutPositionProperty"; +#define ASLayoutElementStyleSetSizeWithScope(x) \ + __instanceLock__.lock(); \ + ASLayoutElementSize newSize = _size.load(); \ + { x } \ + _size.store(newSize); \ + __instanceLock__.unlock(); + #define ASLayoutElementStyleCallDelegate(propertyName)\ do {\ [_delegate style:self propertyDidChange:propertyName];\ @@ -117,9 +124,9 @@ void ASLayoutElementPopContext() @implementation ASLayoutElementStyle { ASDN::RecursiveMutex __instanceLock__; - ASLayoutElementSize _size; ASLayoutElementStyleExtensions _extensions; + std::atomic _size; std::atomic _spacingBefore; std::atomic _spacingAfter; std::atomic _flexGrow; @@ -173,185 +180,190 @@ - (instancetype)init - (ASLayoutElementSize)size { - ASDN::MutexLocker l(__instanceLock__); - return _size; + return _size.load(); } - (void)setSize:(ASLayoutElementSize)size { - ASDN::MutexLocker l(__instanceLock__); - _size = size; + ASLayoutElementStyleSetSizeWithScope({ + newSize = size; + }); + // No CallDelegate method as ASLayoutElementSize is currently internal. } #pragma mark - ASLayoutElementStyleSizeForwarding - (ASDimension)width { - ASDN::MutexLocker l(__instanceLock__); - return _size.width; + return _size.load().width; } - (void)setWidth:(ASDimension)width { - ASDN::MutexLocker l(__instanceLock__); - _size.width = width; + ASLayoutElementStyleSetSizeWithScope({ + newSize.width = width; + }); ASLayoutElementStyleCallDelegate(ASLayoutElementStyleWidthProperty); } - (ASDimension)height { - ASDN::MutexLocker l(__instanceLock__); - return _size.height; + return _size.load().height; } - (void)setHeight:(ASDimension)height { - ASDN::MutexLocker l(__instanceLock__); - _size.height = height; + ASLayoutElementStyleSetSizeWithScope({ + newSize.height = height; + }); ASLayoutElementStyleCallDelegate(ASLayoutElementStyleHeightProperty); } - (ASDimension)minWidth { - ASDN::MutexLocker l(__instanceLock__); - return _size.minWidth; + return _size.load().minWidth; } - (void)setMinWidth:(ASDimension)minWidth { - ASDN::MutexLocker l(__instanceLock__); - _size.minWidth = minWidth; + ASLayoutElementStyleSetSizeWithScope({ + newSize.minWidth = minWidth; + }); ASLayoutElementStyleCallDelegate(ASLayoutElementStyleMinWidthProperty); } - (ASDimension)maxWidth { - ASDN::MutexLocker l(__instanceLock__); - return _size.maxWidth; + return _size.load().maxWidth; } - (void)setMaxWidth:(ASDimension)maxWidth { - ASDN::MutexLocker l(__instanceLock__); - _size.maxWidth = maxWidth; + ASLayoutElementStyleSetSizeWithScope({ + newSize.maxWidth = maxWidth; + }); ASLayoutElementStyleCallDelegate(ASLayoutElementStyleMaxWidthProperty); } - (ASDimension)minHeight { - ASDN::MutexLocker l(__instanceLock__); - return _size.minHeight; + return _size.load().minHeight; } - (void)setMinHeight:(ASDimension)minHeight { - ASDN::MutexLocker l(__instanceLock__); - _size.minHeight = minHeight; + ASLayoutElementStyleSetSizeWithScope({ + newSize.minHeight = minHeight; + }); ASLayoutElementStyleCallDelegate(ASLayoutElementStyleMinHeightProperty); } - (ASDimension)maxHeight { - ASDN::MutexLocker l(__instanceLock__); - return _size.maxHeight; + return _size.load().maxHeight; } - (void)setMaxHeight:(ASDimension)maxHeight { - ASDN::MutexLocker l(__instanceLock__); - _size.maxHeight = maxHeight; + ASLayoutElementStyleSetSizeWithScope({ + newSize.maxHeight = maxHeight; + }); ASLayoutElementStyleCallDelegate(ASLayoutElementStyleMaxHeightProperty); } #pragma mark - ASLayoutElementStyleSizeHelpers -// We explicitly not call the setter for (max/min) width and height to avoid locking overhead - - (void)setPreferredSize:(CGSize)preferredSize { - ASDN::MutexLocker l(__instanceLock__); - _size.width = ASDimensionMakeWithPoints(preferredSize.width); - _size.height = ASDimensionMakeWithPoints(preferredSize.height); + ASLayoutElementStyleSetSizeWithScope({ + newSize.width = ASDimensionMakeWithPoints(preferredSize.width); + newSize.height = ASDimensionMakeWithPoints(preferredSize.height); + }); ASLayoutElementStyleCallDelegate(ASLayoutElementStyleWidthProperty); ASLayoutElementStyleCallDelegate(ASLayoutElementStyleHeightProperty); } - (CGSize)preferredSize { - ASDN::MutexLocker l(__instanceLock__); - if (_size.width.unit == ASDimensionUnitFraction) { - NSCAssert(NO, @"Cannot get preferredSize of element with fractional width. Width: %@.", NSStringFromASDimension(_size.width)); + ASLayoutElementSize size = _size.load(); + if (size.width.unit == ASDimensionUnitFraction) { + NSCAssert(NO, @"Cannot get preferredSize of element with fractional width. Width: %@.", NSStringFromASDimension(size.width)); return CGSizeZero; } - if (_size.height.unit == ASDimensionUnitFraction) { - NSCAssert(NO, @"Cannot get preferredSize of element with fractional height. Height: %@.", NSStringFromASDimension(_size.height)); + if (size.height.unit == ASDimensionUnitFraction) { + NSCAssert(NO, @"Cannot get preferredSize of element with fractional height. Height: %@.", NSStringFromASDimension(size.height)); return CGSizeZero; } - return CGSizeMake(_size.width.value, _size.height.value); + return CGSizeMake(size.width.value, size.height.value); } - (void)setMinSize:(CGSize)minSize { - ASDN::MutexLocker l(__instanceLock__); - _size.minWidth = ASDimensionMakeWithPoints(minSize.width); - _size.minHeight = ASDimensionMakeWithPoints(minSize.height); + ASLayoutElementStyleSetSizeWithScope({ + newSize.minWidth = ASDimensionMakeWithPoints(minSize.width); + newSize.minHeight = ASDimensionMakeWithPoints(minSize.height); + }); ASLayoutElementStyleCallDelegate(ASLayoutElementStyleMinWidthProperty); ASLayoutElementStyleCallDelegate(ASLayoutElementStyleMinHeightProperty); } - (void)setMaxSize:(CGSize)maxSize { - ASDN::MutexLocker l(__instanceLock__); - _size.maxWidth = ASDimensionMakeWithPoints(maxSize.width); - _size.maxHeight = ASDimensionMakeWithPoints(maxSize.height); + ASLayoutElementStyleSetSizeWithScope({ + newSize.maxWidth = ASDimensionMakeWithPoints(maxSize.width); + newSize.maxHeight = ASDimensionMakeWithPoints(maxSize.height); + }); ASLayoutElementStyleCallDelegate(ASLayoutElementStyleMaxWidthProperty); ASLayoutElementStyleCallDelegate(ASLayoutElementStyleMaxHeightProperty); } - (ASLayoutSize)preferredLayoutSize { - ASDN::MutexLocker l(__instanceLock__); - return ASLayoutSizeMake(_size.width, _size.height); + ASLayoutElementSize size = _size.load(); + return ASLayoutSizeMake(size.width, size.height); } - (void)setPreferredLayoutSize:(ASLayoutSize)preferredLayoutSize { - ASDN::MutexLocker l(__instanceLock__); - _size.width = preferredLayoutSize.width; - _size.height = preferredLayoutSize.height; + ASLayoutElementStyleSetSizeWithScope({ + newSize.width = preferredLayoutSize.width; + newSize.height = preferredLayoutSize.height; + }); ASLayoutElementStyleCallDelegate(ASLayoutElementStyleWidthProperty); ASLayoutElementStyleCallDelegate(ASLayoutElementStyleHeightProperty); } - (ASLayoutSize)minLayoutSize { - ASDN::MutexLocker l(__instanceLock__); - return ASLayoutSizeMake(_size.minWidth, _size.minHeight); + ASLayoutElementSize size = _size.load(); + return ASLayoutSizeMake(size.minWidth, size.minHeight); } - (void)setMinLayoutSize:(ASLayoutSize)minLayoutSize { - ASDN::MutexLocker l(__instanceLock__); - _size.minWidth = minLayoutSize.width; - _size.minHeight = minLayoutSize.height; + ASLayoutElementStyleSetSizeWithScope({ + newSize.minWidth = minLayoutSize.width; + newSize.minHeight = minLayoutSize.height; + }); ASLayoutElementStyleCallDelegate(ASLayoutElementStyleMinWidthProperty); ASLayoutElementStyleCallDelegate(ASLayoutElementStyleMinHeightProperty); } - (ASLayoutSize)maxLayoutSize { - ASDN::MutexLocker l(__instanceLock__); - return ASLayoutSizeMake(_size.maxWidth, _size.maxHeight); + ASLayoutElementSize size = _size.load(); + return ASLayoutSizeMake(size.maxWidth, size.maxHeight); } - (void)setMaxLayoutSize:(ASLayoutSize)maxLayoutSize { - ASDN::MutexLocker l(__instanceLock__); - _size.maxWidth = maxLayoutSize.width; - _size.maxHeight = maxLayoutSize.height; + ASLayoutElementStyleSetSizeWithScope({ + newSize.maxWidth = maxLayoutSize.width; + newSize.maxHeight = maxLayoutSize.height; + }); ASLayoutElementStyleCallDelegate(ASLayoutElementStyleMaxWidthProperty); ASLayoutElementStyleCallDelegate(ASLayoutElementStyleMaxHeightProperty); }