Title: [266717] trunk/Source/WebCore
Revision
266717
Author
[email protected]
Date
2020-09-08 01:48:38 -0700 (Tue, 08 Sep 2020)

Log Message

Comparing styles with large but identical custom property maps is slow
https://bugs.webkit.org/show_bug.cgi?id=216241
<rdar://problem/67946605>

Reviewed by Darin Adler.

In a full style rebuild we lose sharing of equal StyleCustomPropertyDatas between the old and the new style.
Custom properties are usually defined in document element and this lack of sharing inherits to all elements.
Without sharing equality comparisons end up requiring deep comparisons, which can be slow if there are thousands of properties.

Fix by deduplicating identical property maps between the old the new style. All the descendants that inherit the properties will
now be cheap to compare.

The patch also contains some other basic custom property optimizations.

Going to full screen and back on youtube, this patch reduces time in the longest style update from ~460ms to ~90ms.

* css/CSSCustomPropertyValue.cpp:
(WebCore::CSSCustomPropertyValue::equals const):

Check for pointer equality first.

* rendering/style/RenderStyle.cpp:
(WebCore::RenderStyle::deduplicateInheritedCustomProperties):

Deduplicate if the properties are equal but not shared.

(WebCore::RenderStyle::setInheritedCustomPropertyValue):
(WebCore::RenderStyle::setNonInheritedCustomPropertyValue):

Check if the value is already in the map before triggering copy-on-write.

* rendering/style/RenderStyle.h:
(WebCore::RenderStyle::setInheritedCustomPropertyValue): Deleted.
(WebCore::RenderStyle::setNonInheritedCustomPropertyValue): Deleted.
* style/StyleBuilder.cpp:
(WebCore::Style::Builder::applyCustomProperty):

Don't create unnecesary copies of CSSCustomPropertyValue.

* style/StyleTreeResolver.cpp:
(WebCore::Style::TreeResolver::createAnimatedElementUpdate):

Try to deduplicate before comparing the styles.

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (266716 => 266717)


--- trunk/Source/WebCore/ChangeLog	2020-09-08 07:35:49 UTC (rev 266716)
+++ trunk/Source/WebCore/ChangeLog	2020-09-08 08:48:38 UTC (rev 266717)
@@ -1,3 +1,50 @@
+2020-09-08  Antti Koivisto  <[email protected]>
+
+        Comparing styles with large but identical custom property maps is slow
+        https://bugs.webkit.org/show_bug.cgi?id=216241
+        <rdar://problem/67946605>
+
+        Reviewed by Darin Adler.
+
+        In a full style rebuild we lose sharing of equal StyleCustomPropertyDatas between the old and the new style.
+        Custom properties are usually defined in document element and this lack of sharing inherits to all elements.
+        Without sharing equality comparisons end up requiring deep comparisons, which can be slow if there are thousands of properties.
+
+        Fix by deduplicating identical property maps between the old the new style. All the descendants that inherit the properties will
+        now be cheap to compare.
+
+        The patch also contains some other basic custom property optimizations.
+
+        Going to full screen and back on youtube, this patch reduces time in the longest style update from ~460ms to ~90ms.
+
+        * css/CSSCustomPropertyValue.cpp:
+        (WebCore::CSSCustomPropertyValue::equals const):
+
+        Check for pointer equality first.
+
+        * rendering/style/RenderStyle.cpp:
+        (WebCore::RenderStyle::deduplicateInheritedCustomProperties):
+
+        Deduplicate if the properties are equal but not shared.
+
+        (WebCore::RenderStyle::setInheritedCustomPropertyValue):
+        (WebCore::RenderStyle::setNonInheritedCustomPropertyValue):
+
+        Check if the value is already in the map before triggering copy-on-write.
+
+        * rendering/style/RenderStyle.h:
+        (WebCore::RenderStyle::setInheritedCustomPropertyValue): Deleted.
+        (WebCore::RenderStyle::setNonInheritedCustomPropertyValue): Deleted.
+        * style/StyleBuilder.cpp:
+        (WebCore::Style::Builder::applyCustomProperty):
+
+        Don't create unnecesary copies of CSSCustomPropertyValue.
+
+        * style/StyleTreeResolver.cpp:
+        (WebCore::Style::TreeResolver::createAnimatedElementUpdate):
+
+        Try to deduplicate before comparing the styles.
+
 2020-09-07  Sergio Villar Senin  <[email protected]>
 
         [css-flex] Don't skip flexboxes with auto height for percentage computations in quirks mode

Modified: trunk/Source/WebCore/css/CSSCustomPropertyValue.cpp (266716 => 266717)


--- trunk/Source/WebCore/css/CSSCustomPropertyValue.cpp	2020-09-08 07:35:49 UTC (rev 266716)
+++ trunk/Source/WebCore/css/CSSCustomPropertyValue.cpp	2020-09-08 08:48:38 UTC (rev 266717)
@@ -31,6 +31,8 @@
 
 bool CSSCustomPropertyValue::equals(const CSSCustomPropertyValue& other) const
 {
+    if (this == &other)
+        return true;
     if (m_name != other.m_name || m_value.index() != other.m_value.index())
         return false;
     return WTF::switchOn(m_value, [&](const Ref<CSSVariableReferenceValue>& value) {

Modified: trunk/Source/WebCore/rendering/style/RenderStyle.cpp (266716 => 266717)


--- trunk/Source/WebCore/rendering/style/RenderStyle.cpp	2020-09-08 07:35:49 UTC (rev 266716)
+++ trunk/Source/WebCore/rendering/style/RenderStyle.cpp	2020-09-08 08:48:38 UTC (rev 266717)
@@ -2341,6 +2341,30 @@
     }
 }
 
+void RenderStyle::deduplicateInheritedCustomProperties(const RenderStyle& other)
+{
+    auto& properties = const_cast<DataRef<StyleCustomPropertyData>&>(m_rareInheritedData->customProperties);
+    auto& otherProperties = other.m_rareInheritedData->customProperties;
+    if (properties.ptr() != otherProperties.ptr() && *properties == *otherProperties)
+        properties = otherProperties;
+}
+
+void RenderStyle::setInheritedCustomPropertyValue(const AtomString& name, Ref<CSSCustomPropertyValue>&& value)
+{
+    auto* existingValue = m_rareInheritedData->customProperties->values.get(name);
+    if (existingValue && existingValue->equals(value.get()))
+        return;
+    m_rareInheritedData.access().customProperties.access().setCustomPropertyValue(name, WTFMove(value));
+}
+
+void RenderStyle::setNonInheritedCustomPropertyValue(const AtomString& name, Ref<CSSCustomPropertyValue>&& value)
+{
+    auto* existingValue = m_rareNonInheritedData->customProperties->values.get(name);
+    if (existingValue && existingValue->equals(value.get()))
+        return;
+    m_rareNonInheritedData.access().customProperties.access().setCustomPropertyValue(name, WTFMove(value));
+}
+
 #if ENABLE(CSS_SCROLL_SNAP)
 
 ScrollSnapType RenderStyle::initialScrollSnapType()

Modified: trunk/Source/WebCore/rendering/style/RenderStyle.h (266716 => 266717)


--- trunk/Source/WebCore/rendering/style/RenderStyle.h	2020-09-08 07:35:49 UTC (rev 266716)
+++ trunk/Source/WebCore/rendering/style/RenderStyle.h	2020-09-08 08:48:38 UTC (rev 266717)
@@ -183,11 +183,12 @@
 
     const PseudoStyleCache* cachedPseudoStyles() const { return m_cachedPseudoStyles.get(); }
 
+    void deduplicateInheritedCustomProperties(const RenderStyle&);
     const CustomPropertyValueMap& inheritedCustomProperties() const { return m_rareInheritedData->customProperties->values; }
     const CustomPropertyValueMap& nonInheritedCustomProperties() const { return m_rareNonInheritedData->customProperties->values; }
     const CSSCustomPropertyValue* getCustomProperty(const AtomString&) const;
-    void setInheritedCustomPropertyValue(const AtomString& name, Ref<CSSCustomPropertyValue>&& value) { return m_rareInheritedData.access().customProperties.access().setCustomPropertyValue(name, WTFMove(value)); }
-    void setNonInheritedCustomPropertyValue(const AtomString& name, Ref<CSSCustomPropertyValue>&& value) { return m_rareNonInheritedData.access().customProperties.access().setCustomPropertyValue(name, WTFMove(value)); }
+    void setInheritedCustomPropertyValue(const AtomString& name, Ref<CSSCustomPropertyValue>&&);
+    void setNonInheritedCustomPropertyValue(const AtomString& name, Ref<CSSCustomPropertyValue>&&);
 
     void setHasViewportUnits(bool v = true) { m_nonInheritedFlags.hasViewportUnits = v; }
     bool hasViewportUnits() const { return m_nonInheritedFlags.hasViewportUnits; }

Modified: trunk/Source/WebCore/style/StyleBuilder.cpp (266716 => 266717)


--- trunk/Source/WebCore/style/StyleBuilder.cpp	2020-09-08 07:35:49 UTC (rev 266716)
+++ trunk/Source/WebCore/style/StyleBuilder.cpp	2020-09-08 08:48:38 UTC (rev 266717)
@@ -195,7 +195,7 @@
         if (index != SelectorChecker::MatchDefault && m_state.style().insideLink() == InsideLink::NotInside)
             continue;
 
-        Ref<CSSCustomPropertyValue> valueToApply = CSSCustomPropertyValue::create(downcast<CSSCustomPropertyValue>(*property.cssValue[index]));
+        auto valueToApply = makeRef(downcast<CSSCustomPropertyValue>(*property.cssValue[index]));
 
         if (inCycle) {
             m_state.m_appliedCustomProperties.add(name); // Make sure we do not try to apply this property again while resolving it.
@@ -231,7 +231,7 @@
         if (index != SelectorChecker::MatchDefault && m_state.style().insideLink() == InsideLink::NotInside)
             continue;
 
-        Ref<CSSCustomPropertyValue> valueToApply = CSSCustomPropertyValue::create(downcast<CSSCustomPropertyValue>(*property.cssValue[index]));
+        auto valueToApply = makeRef(downcast<CSSCustomPropertyValue>(*property.cssValue[index]));
 
         if (inCycle && WTF::holds_alternative<Ref<CSSVariableReferenceValue>>(valueToApply->value())) {
             // Resolve this value so that we reset its dependencies.

Modified: trunk/Source/WebCore/style/StyleTreeResolver.cpp (266716 => 266717)


--- trunk/Source/WebCore/style/StyleTreeResolver.cpp	2020-09-08 07:35:49 UTC (rev 266716)
+++ trunk/Source/WebCore/style/StyleTreeResolver.cpp	2020-09-08 08:48:38 UTC (rev 266717)
@@ -361,6 +361,11 @@
     if (animationImpact)
         Adjuster::adjustAnimatedStyle(*newStyle, parentBoxStyle(), animationImpact);
 
+    // Deduplication speeds up equality comparisons as the properties inherit to descendants.
+    // FIXME: There should be a more general mechanism for this.
+    if (oldStyle)
+        newStyle->deduplicateInheritedCustomProperties(*oldStyle);
+
     auto change = oldStyle ? determineChange(*oldStyle, *newStyle) : Detach;
 
     auto validity = element.styleValidity();
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to