RESOLVED FIXED308946
contain: layout causes ~8x regression in forced synchronous reflow on in-flow elements
https://bugs.webkit.org/show_bug.cgi?id=308946
Summary contain: layout causes ~8x regression in forced synchronous reflow on in-flow...
chenglou92
Reported 2026-03-01 19:48:16 PST
Created attachment 478537 [details] Repro Adding contain: layout (or contain: strict, contain: content, contain: size layout) to in-flow position: relative elements causes a ~7-8x performance regression during interleaved read/write DOM access patterns (forced synchronous reflow), compared to the same elements without containment. overflow: hidden on in-flow elements exhibits the same regression. Repro: 1. Open the attached HTML file 2. Observe the printed timing ratio Expected: contain: layout should be equal or faster than baseline, since it restricts layout scope. Actual: contain: layout is ~7-8x slower than baseline. Test results on Safari baseline (position:relative): ~69ms + contain:layout: ~539ms ratio: ~7.8x Chrome, same hardware & OS: baseline (position:relative): ~43ms + contain:layout: ~32ms ratio: ~0.75x (faster, as expected) Batched access (all writes then all reads) shows no regression — both ~4-6ms. The issue is specific to forced synchronous reflow triggered by interleaved write-then-read patterns.
Attachments
Repro (1.59 KB, text/html)
2026-03-01 19:48 PST, chenglou92
no flags
Simon Fraser (smfr)
Comment 1 2026-03-02 11:22:09 PST
Surprising!
Radar WebKit Bug Importer
Comment 2 2026-03-02 11:22:16 PST
Simon Fraser (smfr)
Comment 3 2026-03-02 11:47:29 PST
(Look at the relative %, not the actual %): Without contain: Sample Count, Samples%, Normalized CPU %, Symbol 24, 26.7%, 1.2%, WebCore::Element::offsetHeight() (in WebCore) 24, 26.7%, 1.2%, WebCore::Document::updateLayoutIfDimensionsOutOfDate(WebCore::Element&, WTF::OptionSet<WebCore::DimensionsCheck, (WTF::ConcurrencyTag)0>, WTF::OptionSet<WebCore::LayoutOptions, (WTF::ConcurrencyTag)0>) (in WebCore) 22, 24.4%, 1.1%, WebCore::Document::updateLayout(WTF::OptionSet<WebCore::LayoutOptions, (WTF::ConcurrencyTag)0>, WebCore::Element const*) (in WebCore) 22, 24.4%, 1.1%, WebCore::LocalFrameViewLayoutContext::layout(bool) (in WebCore) 22, 24.4%, 1.1%, WebCore::LocalFrameViewLayoutContext::performLayout(bool) (in WebCore) 13, 14.4%, 0.7%, WebCore::LocalFrameViewLayoutContext::flushUpdateLayerPositions() (in WebCore) 13, 14.4%, 0.7%, void WebCore::RenderLayer::recursiveUpdateLayerPositions<(WebCore::RenderLayer::UpdateLayerPositionsMode)0>(WTF::OptionSet<WebCore::RenderLayer::UpdateLayerPositionsFlag, (WTF::ConcurrencyTag)0>) (in WebCore) 9, 10.0%, 0.5%, WebCore::RenderView::layout() (in WebCore) 9, 10.0%, 0.5%, WebCore::RenderBlock::layout() (in WebCore) 9, 10.0%, 0.5%, WebCore::RenderBlockFlow::layoutBlock(WebCore::RelayoutChildren, WebCore::LayoutUnit) (in WebCore) 9, 10.0%, 0.5%, WebCore::RenderBlockFlow::layoutBlockChildren(WebCore::RelayoutChildren, WebCore::LayoutUnit&) (in WebCore) 9, 10.0%, 0.5%, WebCore::RenderBlockFlow::layoutBlockChild(WebCore::RenderBox&, WebCore::RenderBlockFlow::MarginInfo&, WebCore::LayoutUnit&, WebCore::LayoutUnit&) (in WebCore) 3, 3.3%, 0.2%, WebCore::RenderBox::avoidsFloats() const (in WebCore) With contain: Sample Count, Samples%, Normalized CPU %, Symbol 304, 48.3%, 2.1%, WebCore::Element::offsetHeight() (in WebCore) 304, 48.3%, 2.1%, WebCore::Document::updateLayoutIfDimensionsOutOfDate(WebCore::Element&, WTF::OptionSet<WebCore::DimensionsCheck, (WTF::ConcurrencyTag)0>, WTF::OptionSet<WebCore::LayoutOptions, (WTF::ConcurrencyTag)0>) (in WebCore) 299, 47.5%, 2.1%, WebCore::Document::updateLayout(WTF::OptionSet<WebCore::LayoutOptions, (WTF::ConcurrencyTag)0>, WebCore::Element const*) (in WebCore) 299, 47.5%, 2.1%, WebCore::LocalFrameViewLayoutContext::layout(bool) (in WebCore) 299, 47.5%, 2.1%, WebCore::LocalFrameViewLayoutContext::performLayout(bool) (in WebCore) 287, 45.6%, 2.0%, WebCore::RenderView::layout() (in WebCore) 287, 45.6%, 2.0%, WebCore::RenderBlock::layout() (in WebCore) 287, 45.6%, 2.0%, WebCore::RenderBlockFlow::layoutBlock(WebCore::RelayoutChildren, WebCore::LayoutUnit) (in WebCore) 287, 45.6%, 2.0%, WebCore::RenderBlockFlow::layoutBlockChildren(WebCore::RelayoutChildren, WebCore::LayoutUnit&) (in WebCore) 287, 45.6%, 2.0%, WebCore::RenderBlockFlow::layoutBlockChild(WebCore::RenderBox&, WebCore::RenderBlockFlow::MarginInfo&, WebCore::LayoutUnit&, WebCore::LayoutUnit&) (in WebCore) 209, 33.2%, 1.5%, WebCore::RenderBlock::createsNewFormattingContext() const (in WebCore) 20, 3.2%, 0.1%, WebCore::RenderBlock::layout() (in WebCore) 20, 3.2%, 0.1%, WebCore::RenderBlockFlow::layoutBlock(WebCore::RelayoutChildren, WebCore::LayoutUnit) (in WebCore) 16, 2.5%, 0.1%, WebCore::RenderBlockFlow::layoutBlockChildren(WebCore::RelayoutChildren, WebCore::LayoutUnit&) (in WebCore)
Yulun Wu
Comment 4 2026-03-20 22:59:42 PDT
EWS
Comment 5 2026-03-28 23:08:00 PDT
Committed 310173@main (541a1c2870a0): <https://commits.webkit.org/310173@main> Reviewed commits have been landed. Closing PR #61069 and removing active labels.
Note You need to log in before you can comment on or make changes to this bug.