We waste time updating timers during a rendering update: Style recalc timer: CFRunLoopTimerSetNextFireDate WebCore::MainThreadSharedTimer::setFireInterval(WTF::Seconds) WebCore::ThreadTimers::updateSharedTimer() WebCore::TimerBase::setNextFireTime(WTF::MonotonicTime) WebCore::TimerBase::start(WTF::Seconds, WTF::Seconds) WebCore::TimerBase::startOneShot(WTF::Seconds) WebCore::Document::scheduleStyleRecalc() WebCore::Node::updateAncestorsForStyleRecalc() WebCore::Node::invalidateStyle(WebCore::Style::Validity, WebCore::Style::InvalidationMode) WebCore::Element::invalidateStyle() WebCore::StyledElement::invalidateStyleAttribute() WebCore::InlineCSSStyleDeclaration::didMutate(WebCore::PropertySetCSSStyleDeclaration::MutationType) WebCore::PropertySetCSSStyleDeclaration::setPropertyInternal(WebCore::CSSPropertyID, WTF::String const&, bool) WebCore::CSSStyleDeclaration::setNamedItem(WTF::AtomString const&, WTF::String, bool&) WebCore::JSCSSStyleDeclaration::put(JSC::JSCell*, JSC::JSGlobalObject*, JSC::PropertyName, JSC::JSValue, JSC::PutPropertySlot&) JSC::JSCell::putInline(JSC::JSGlobalObject*, JSC::PropertyName, JSC::JSValue, JSC::PutPropertySlot&) JSC::JSValue::putInline(JSC::JSGlobalObject*, JSC::PropertyName, JSC::JSValue, JSC::PutPropertySlot&) operationPutByIdNonStrict 0x4ed07c0002cd vmEntryToJavaScript JSC::JITCode::execute(JSC::VM*, JSC::ProtoCallFrame*) JSC::Interpreter::executeCall(JSC::JSGlobalObject*, JSC::JSObject*, JSC::CallType, JSC::CallData const&, JSC::JSValue, JSC::ArgList const&) JSC::call(JSC::JSGlobalObject*, JSC::JSValue, JSC::CallType, JSC::CallData const&, JSC::JSValue, JSC::ArgList const&) JSC::call(JSC::JSGlobalObject*, JSC::JSValue, JSC::CallType, JSC::CallData const&, JSC::JSValue, JSC::ArgList const&, WTF::NakedPtr<JSC::Exception>&) JSC::profiledCall(JSC::JSGlobalObject*, JSC::ProfilingReason, JSC::JSValue, JSC::CallType, JSC::CallData const&, JSC::JSValue, JSC::ArgList const&, WTF::NakedPtr<JSC::Exception>&) WebCore::JSExecState::profiledCall(JSC::JSGlobalObject*, JSC::ProfilingReason, JSC::JSValue, JSC::CallType, JSC::CallData const&, JSC::JSValue, JSC::ArgList const&, WTF::NakedPtr<JSC::Exception>&) WebCore::JSEventListener::handleEvent(WebCore::ScriptExecutionContext&, WebCore::Event&) WebCore::EventTarget::innerInvokeEventListeners(WebCore::Event&, WTF::Vector<WTF::RefPtr<WebCore::RegisteredEventListener, WTF::DumbPtrTraits<WebCore::RegisteredEventListener> >, 1ul, WTF::CrashOnOverflow, 16ul, WTF::FastMalloc>, WebCore::EventTarget::EventInvokePhase) WebCore::EventTarget::fireEventListeners(WebCore::Event&, WebCore::EventTarget::EventInvokePhase) WebCore::WindowEventContext::handleLocalEvents(WebCore::Event&, WebCore::EventTarget::EventInvokePhase) const WebCore::dispatchEventInDOM(WebCore::Event&, WebCore::EventPath const&) WebCore::EventDispatcher::dispatchEvent(WebCore::Node&, WebCore::Event&) WebCore::Node::dispatchEvent(WebCore::Event&) WebCore::Document::runScrollSteps() WebCore::Page::updateRendering()::$_13::operator()(WebCore::Document&) const CFRunLoopTimerSetNextFireDate WebCore::MainThreadSharedTimer::setFireInterval(WTF::Seconds) WebCore::ThreadTimers::updateSharedTimer() WebCore::TimerBase::setNextFireTime(WTF::MonotonicTime) WebCore::TimerBase::stop() WebCore::Document::unscheduleStyleRecalc() WebCore::Document::resolveStyle(WebCore::Document::ResolveStyleType) WebCore::Document::updateStyleIfNeeded() WebCore::FrameView::updateLayoutAndStyleIfNeededRecursive() WebCore::Page::layoutIfNeeded() WebCore::Page::updateRendering() WebKit::WebPage::updateRendering() Layout timer: WebCore::MainThreadSharedTimer::setFireInterval(WTF::Seconds) WebCore::ThreadTimers::updateSharedTimer() WebCore::TimerBase::setNextFireTime(WTF::MonotonicTime) WebCore::TimerBase::start(WTF::Seconds, WTF::Seconds) WebCore::TimerBase::startOneShot(WTF::Seconds) WebCore::FrameViewLayoutContext::scheduleLayout() WebCore::scheduleRelayoutForSubtree(WebCore::RenderElement&) WebCore::RenderObject::markContainingBlocksForLayout(WebCore::ScheduleRelayout, WebCore::RenderElement*) WebCore::RenderElement::setNeedsPositionedMovementLayout(WebCore::RenderStyle const*) WebCore::RenderElement::styleDidChange(WebCore::StyleDifference, WebCore::RenderStyle const*) WebCore::RenderLayerModelObject::styleDidChange(WebCore::StyleDifference, WebCore::RenderStyle const*) WebCore::RenderBox::styleDidChange(WebCore::StyleDifference, WebCore::RenderStyle const*) WebCore::RenderBlock::styleDidChange(WebCore::StyleDifference, WebCore::RenderStyle const*) WebCore::RenderBlockFlow::styleDidChange(WebCore::StyleDifference, WebCore::RenderStyle const*) WebCore::RenderElement::setStyle(WebCore::RenderStyle&&, WebCore::StyleDifference) WebCore::RenderTreeUpdater::updateRendererStyle(WebCore::RenderElement&, WebCore::RenderStyle&&, WebCore::StyleDifference) WebCore::TimerBase::stop() WebCore::FrameViewLayoutContext::layout() WebCore::FrameView::updateLayoutAndStyleIfNeededRecursive() WebCore::Page::layoutIfNeeded() WebCore::Page::updateRendering() WebKit::WebPage::updateRendering() Scrolling tree commit timer: WebCore::TimerBase::start(WTF::Seconds, WTF::Seconds) WebCore::TimerBase::startOneShot(WTF::Seconds) WebCore::ScrollingCoordinatorMac::scheduleTreeStateCommit() WebCore::AsyncScrollingCoordinator::scrollingStateTreePropertiesChanged() WebCore::ScrollingStateTree::setHasChangedProperties(bool) WebCore::ScrollingStateNode::setPropertyChanged(unsigned int) WebCore::ScrollingStateScrollingNode::setScrollPosition(WebCore::FloatPoint const&) WebCore::AsyncScrollingCoordinator::setScrollingNodeScrollableAreaGeometry(unsigned long long, WebCore::ScrollableArea&) WebCore::RenderLayerCompositor::updateScrollingNodeForScrollingRole(WebCore::RenderLayer&, WebCore::ScrollingTreeState&, WTF::OptionSet<WebCore::RenderLayerCompositor::ScrollingNodeChangeFlags>) WebCore::RenderLayerCompositor::updateScrollCoordinationForLayer(WebCore::RenderLayer&, WebCore::RenderLayer const*, WebCore::ScrollingTreeState&, WTF::OptionSet<WebCore::RenderLayerCompositor::ScrollingNodeChangeFlags>) WebCore::RenderLayerCompositor::updateBackingAndHierarchy(WebCore::RenderLayer&, WTF::Vector<WTF::Ref<WebCore::GraphicsLayer, WTF::DumbPtrTraits<WebCore::GraphicsLayer> >, 0ul, WTF::CrashOnOverflow, 16ul, WTF::FastMalloc>&, WebCore::RenderLayerCompositor::UpdateBackingTraversalState&, WebCore::ScrollingTreeState&, WTF::OptionSet<WebCore::RenderLayerCompositor::UpdateLevel>) WebCore::RenderLayerCompositor::updateCompositingLayers(WebCore::CompositingUpdateType, WebCore::RenderLayer*) WebCore::FrameView::updateCompositingLayersAfterLayout() WebCore::FrameView::didLayout(WTF::WeakPtr<WebCore::RenderElement>) WebCore::FrameViewLayoutContext::layout() WebCore::FrameView::updateLayoutAndStyleIfNeededRecursive() WebCore::Page::layoutIfNeeded() WebCore::Page::updateRendering() WebKit::WebPage::updateRendering() None of these are necessary.
Should we add some flag on Document to indicate that we're in the middle of rendering update?
Also, in theory, we should never have to schedule style recalc / layout anymore directly.
Pull request: https://github.com/WebKit/WebKit/pull/16213
I think the scheduleLayout case is not happening anymore, at least I could not reproduce it.