- Revision
- 266677
- Author
- wenson_hs...@apple.com
- Date
- 2020-09-05 18:36:12 -0700 (Sat, 05 Sep 2020)
Log Message
[MotionMark] RenderLayer::paintLayerContents spends ~5% of the time in MonotonicTime::now() in Multiply
https://bugs.webkit.org/show_bug.cgi?id=216190
Reviewed by Darin Adler.
Source/WebCore:
In several of MotionMark's subtests (for instance, Multiply), we spent a large amount of time underneath
`RenderLayer::paintLayerContents` due to both the large number of layers and the need to frequently repaint
each layer (all of which are constantly being animated). Underneath this method, a nontrivial amount of time
(~5%) is then spent grabbing the system time via `MonotonicTime::now()`.
We can avoid this extra work by instead using the timestamp of the last rendering update (before we started
painting), which we keep track of using a new member variable on `Page`. See below for more details, as well as
the WebKit2 ChangeLog.
* page/ChromeClient.h:
(WebCore::ChromeClient::timestampForPaintFrequencyTracking const):
Add a client hook to fetch the timestamp to use when tracking painting frequency. See the WebKit2 ChangeLog for
more details.
* page/Page.cpp:
(WebCore::Page::updateRendering):
Update `m_lastRenderingUpdateTimestamp`.
* page/Page.h:
(WebCore::Page::lastRenderingUpdateTimestamp const):
* rendering/PaintFrequencyTracker.h:
Drive-by cleanup: narrow the `PaintFrequency` enum to `bool` width.
(WebCore::PaintFrequencyTracker::begin):
(WebCore::SinglePaintFrequencyTracking::SinglePaintFrequencyTracking):
* rendering/RenderLayer.cpp:
(WebCore::RenderLayer::paintLayerContents):
Call out to the client layer to return a timestamp for tracking painting frequency. By default, this is simply
the current time (`MonotonicTime::now()`), but ports (namely, WebKit2) may opt for a coarser granularity.
(WebCore::RenderLayer::simulateFrequentPaint):
* rendering/RenderLayer.h:
Source/WebKit:
* WebProcess/WebCoreSupport/WebChromeClient.cpp:
(WebKit::WebChromeClient::timestampForPaintFrequencyTracking const):
In WebKit2, we can assume (with the exception of SVG pages) that we must've performed a rendering update prior
to tracking painting frequencies. As such, we can use the page's rendering update timestamp instead of the real
current time (`MonotonicTime::now()`).
Note that in WebKit1, it is possible for any client to force a synchronous paint of the page before the page has
performed a rendering update, which triggers assertions in `SinglePaintFrequencyTracking::end()`. As such, we
stick with `MonotonicTime::now()` in WebKit1.
* WebProcess/WebCoreSupport/WebChromeClient.h:
Modified Paths
Diff
Modified: trunk/Source/WebCore/ChangeLog (266676 => 266677)
--- trunk/Source/WebCore/ChangeLog 2020-09-06 00:44:06 UTC (rev 266676)
+++ trunk/Source/WebCore/ChangeLog 2020-09-06 01:36:12 UTC (rev 266677)
@@ -1,3 +1,47 @@
+2020-09-05 Wenson Hsieh <wenson_hs...@apple.com>
+
+ [MotionMark] RenderLayer::paintLayerContents spends ~5% of the time in MonotonicTime::now() in Multiply
+ https://bugs.webkit.org/show_bug.cgi?id=216190
+
+ Reviewed by Darin Adler.
+
+ In several of MotionMark's subtests (for instance, Multiply), we spent a large amount of time underneath
+ `RenderLayer::paintLayerContents` due to both the large number of layers and the need to frequently repaint
+ each layer (all of which are constantly being animated). Underneath this method, a nontrivial amount of time
+ (~5%) is then spent grabbing the system time via `MonotonicTime::now()`.
+
+ We can avoid this extra work by instead using the timestamp of the last rendering update (before we started
+ painting), which we keep track of using a new member variable on `Page`. See below for more details, as well as
+ the WebKit2 ChangeLog.
+
+ * page/ChromeClient.h:
+ (WebCore::ChromeClient::timestampForPaintFrequencyTracking const):
+
+ Add a client hook to fetch the timestamp to use when tracking painting frequency. See the WebKit2 ChangeLog for
+ more details.
+
+ * page/Page.cpp:
+ (WebCore::Page::updateRendering):
+
+ Update `m_lastRenderingUpdateTimestamp`.
+
+ * page/Page.h:
+ (WebCore::Page::lastRenderingUpdateTimestamp const):
+ * rendering/PaintFrequencyTracker.h:
+
+ Drive-by cleanup: narrow the `PaintFrequency` enum to `bool` width.
+
+ (WebCore::PaintFrequencyTracker::begin):
+ (WebCore::SinglePaintFrequencyTracking::SinglePaintFrequencyTracking):
+ * rendering/RenderLayer.cpp:
+ (WebCore::RenderLayer::paintLayerContents):
+
+ Call out to the client layer to return a timestamp for tracking painting frequency. By default, this is simply
+ the current time (`MonotonicTime::now()`), but ports (namely, WebKit2) may opt for a coarser granularity.
+
+ (WebCore::RenderLayer::simulateFrequentPaint):
+ * rendering/RenderLayer.h:
+
2020-09-05 Sam Weinig <wei...@apple.com>
Fix formatting of LegacyOverrideBuiltIns
Modified: trunk/Source/WebCore/page/ChromeClient.h (266676 => 266677)
--- trunk/Source/WebCore/page/ChromeClient.h 2020-09-06 00:44:06 UTC (rev 266676)
+++ trunk/Source/WebCore/page/ChromeClient.h 2020-09-06 01:36:12 UTC (rev 266677)
@@ -51,6 +51,7 @@
#include <wtf/Assertions.h>
#include <wtf/CompletionHandler.h>
#include <wtf/Forward.h>
+#include <wtf/MonotonicTime.h>
#include <wtf/Seconds.h>
#if ENABLE(WIRELESS_PLAYBACK_TARGET)
@@ -459,6 +460,8 @@
virtual bool shouldUseTiledBackingForFrameView(const FrameView&) const { return false; }
+ virtual MonotonicTime timestampForPaintFrequencyTracking() const { return MonotonicTime::now(); }
+
virtual void isPlayingMediaDidChange(MediaProducer::MediaStateFlags, uint64_t) { }
virtual void handleAutoplayEvent(AutoplayEvent, OptionSet<AutoplayEventFlags>) { }
Modified: trunk/Source/WebCore/page/Page.cpp (266676 => 266677)
--- trunk/Source/WebCore/page/Page.cpp 2020-09-06 00:44:06 UTC (rev 266676)
+++ trunk/Source/WebCore/page/Page.cpp 2020-09-06 01:36:12 UTC (rev 266677)
@@ -1438,6 +1438,8 @@
return;
}
+ m_lastRenderingUpdateTimestamp = MonotonicTime::now();
+
bool isSVGImagePage = chrome().client().isSVGImageChromeClient();
if (!isSVGImagePage)
tracePoint(RenderingUpdateStart);
Modified: trunk/Source/WebCore/page/Page.h (266676 => 266677)
--- trunk/Source/WebCore/page/Page.h 2020-09-06 00:44:06 UTC (rev 266676)
+++ trunk/Source/WebCore/page/Page.h 2020-09-06 01:36:12 UTC (rev 266677)
@@ -775,6 +775,8 @@
bool hasBeenNotifiedToInjectUserScripts() const { return m_hasBeenNotifiedToInjectUserScripts; }
WEBCORE_EXPORT void notifyToInjectUserScripts();
+ MonotonicTime lastRenderingUpdateTimestamp() const { return m_lastRenderingUpdateTimestamp; }
+
private:
struct Navigation {
RegistrableDomain domain;
@@ -1069,6 +1071,8 @@
bool m_canUseCredentialStorage { true };
ShouldRelaxThirdPartyCookieBlocking m_shouldRelaxThirdPartyCookieBlocking { ShouldRelaxThirdPartyCookieBlocking::No };
bool m_hasBeenNotifiedToInjectUserScripts { false };
+
+ MonotonicTime m_lastRenderingUpdateTimestamp;
};
inline PageGroup& Page::group()
Modified: trunk/Source/WebCore/rendering/PaintFrequencyTracker.h (266676 => 266677)
--- trunk/Source/WebCore/rendering/PaintFrequencyTracker.h 2020-09-06 00:44:06 UTC (rev 266676)
+++ trunk/Source/WebCore/rendering/PaintFrequencyTracker.h 2020-09-06 01:36:12 UTC (rev 266677)
@@ -37,7 +37,7 @@
public:
PaintFrequencyTracker() = default;
- void begin()
+ void begin(MonotonicTime timestamp)
{
static unsigned paintFrequencyPaintCountThreshold = 30;
static Seconds paintFrequencyTimePerFrameThreshold = 32_ms;
@@ -46,14 +46,13 @@
// Start by assuming the paint frequency is low
m_paintFrequency = PaintFrequency::Low;
- MonotonicTime now = MonotonicTime::now();
if (!m_firstPaintTime) {
// Handle the first time this method is called.
- m_firstPaintTime = now;
- } else if (now - m_lastPaintTime > paintFrequencySecondsIdleThreshold) {
+ m_firstPaintTime = timestamp;
+ } else if (timestamp - m_lastPaintTime > paintFrequencySecondsIdleThreshold) {
// It has been 5 seconds since last time we draw this renderer. Reset the state
// of this object as if, we've just started tracking the paint frequency.
- m_firstPaintTime = now;
+ m_firstPaintTime = timestamp;
m_totalPaints = 0;
} else if (m_totalPaints >= paintFrequencyPaintCountThreshold && ((m_lastPaintTime - m_firstPaintTime) / m_totalPaints) <= paintFrequencyTimePerFrameThreshold) {
// Change the paint frequency to be high only if:
@@ -62,7 +61,7 @@
m_paintFrequency = PaintFrequency::High;
}
- m_lastPaintTime = now;
+ m_lastPaintTime = timestamp;
++m_totalPaints;
}
@@ -79,7 +78,7 @@
MonotonicTime m_lastPaintTime;
unsigned m_totalPaints { 0 };
- enum class PaintFrequency { Low, High };
+ enum class PaintFrequency : bool { Low, High };
PaintFrequency m_paintFrequency { PaintFrequency::Low };
};
@@ -86,12 +85,12 @@
class SinglePaintFrequencyTracking {
WTF_MAKE_FAST_ALLOCATED;
public:
- SinglePaintFrequencyTracking(PaintFrequencyTracker& paintFrequencyTracker, bool track = true)
+ SinglePaintFrequencyTracking(PaintFrequencyTracker& paintFrequencyTracker, MonotonicTime timestamp, bool track = true)
: m_paintFrequencyTracker(paintFrequencyTracker)
, m_track(track)
{
if (m_track)
- m_paintFrequencyTracker.begin();
+ m_paintFrequencyTracker.begin(timestamp);
}
~SinglePaintFrequencyTracking()
Modified: trunk/Source/WebCore/rendering/RenderLayer.cpp (266676 => 266677)
--- trunk/Source/WebCore/rendering/RenderLayer.cpp 2020-09-06 00:44:06 UTC (rev 266676)
+++ trunk/Source/WebCore/rendering/RenderLayer.cpp 2020-09-06 01:36:12 UTC (rev 266677)
@@ -4629,7 +4629,7 @@
bool selectionAndBackgroundsOnly = paintingInfo.paintBehavior.contains(PaintBehavior::SelectionAndBackgroundsOnly);
bool selectionOnly = paintingInfo.paintBehavior.contains(PaintBehavior::SelectionOnly);
- SinglePaintFrequencyTracking singlePaintFrequencyTracking(m_paintFrequencyTracker, shouldPaintContent);
+ SinglePaintFrequencyTracking singlePaintFrequencyTracking(m_paintFrequencyTracker, page().chrome().client().timestampForPaintFrequencyTracking(), shouldPaintContent && !context.performingPaintInvalidation());
LayerFragments layerFragments;
RenderObject* subtreePaintRootForRenderer = nullptr;
@@ -7025,6 +7025,11 @@
return false;
}
+void RenderLayer::simulateFrequentPaint()
+{
+ SinglePaintFrequencyTracking { m_paintFrequencyTracker, page().chrome().client().timestampForPaintFrequencyTracking() };
+}
+
#if !LOG_DISABLED
static TextStream& operator<<(TextStream& ts, RenderLayer::EventRegionInvalidationReason reason)
{
Modified: trunk/Source/WebCore/rendering/RenderLayer.h (266676 => 266677)
--- trunk/Source/WebCore/rendering/RenderLayer.h 2020-09-06 00:44:06 UTC (rev 266676)
+++ trunk/Source/WebCore/rendering/RenderLayer.h 2020-09-06 01:36:12 UTC (rev 266677)
@@ -920,7 +920,7 @@
bool shouldPlaceBlockDirectionScrollbarOnLeft() const final { return renderer().shouldPlaceBlockDirectionScrollbarOnLeft(); }
- void simulateFrequentPaint() { SinglePaintFrequencyTracking { m_paintFrequencyTracker }; }
+ WEBCORE_EXPORT void simulateFrequentPaint();
bool paintingFrequently() const { return m_paintFrequencyTracker.paintingFrequently(); }
WEBCORE_EXPORT bool isTransparentRespectingParentFrames() const;
Modified: trunk/Source/WebKit/ChangeLog (266676 => 266677)
--- trunk/Source/WebKit/ChangeLog 2020-09-06 00:44:06 UTC (rev 266676)
+++ trunk/Source/WebKit/ChangeLog 2020-09-06 01:36:12 UTC (rev 266677)
@@ -1,3 +1,23 @@
+2020-09-05 Wenson Hsieh <wenson_hs...@apple.com>
+
+ [MotionMark] RenderLayer::paintLayerContents spends ~5% of the time in MonotonicTime::now() in Multiply
+ https://bugs.webkit.org/show_bug.cgi?id=216190
+
+ Reviewed by Darin Adler.
+
+ * WebProcess/WebCoreSupport/WebChromeClient.cpp:
+ (WebKit::WebChromeClient::timestampForPaintFrequencyTracking const):
+
+ In WebKit2, we can assume (with the exception of SVG pages) that we must've performed a rendering update prior
+ to tracking painting frequencies. As such, we can use the page's rendering update timestamp instead of the real
+ current time (`MonotonicTime::now()`).
+
+ Note that in WebKit1, it is possible for any client to force a synchronous paint of the page before the page has
+ performed a rendering update, which triggers assertions in `SinglePaintFrequencyTracking::end()`. As such, we
+ stick with `MonotonicTime::now()` in WebKit1.
+
+ * WebProcess/WebCoreSupport/WebChromeClient.h:
+
2020-09-05 Sam Weinig <wei...@apple.com>
[WebIDL] Realign our IDL extended attribute names with those specified in WebIDL
Modified: trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp (266676 => 266677)
--- trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp 2020-09-06 00:44:06 UTC (rev 266676)
+++ trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp 2020-09-06 01:36:12 UTC (rev 266677)
@@ -1160,6 +1160,11 @@
return m_page.drawingArea()->shouldUseTiledBackingForFrameView(frameView);
}
+MonotonicTime WebChromeClient::timestampForPaintFrequencyTracking() const
+{
+ return isSVGImageChromeClient() ? MonotonicTime::now() : m_page.corePage()->lastRenderingUpdateTimestamp();
+}
+
void WebChromeClient::isPlayingMediaDidChange(MediaProducer::MediaStateFlags state, uint64_t sourceElementID)
{
m_page.send(Messages::WebPageProxy::IsPlayingMediaDidChange(state, sourceElementID));
Modified: trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.h (266676 => 266677)
--- trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.h 2020-09-06 00:44:06 UTC (rev 266676)
+++ trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.h 2020-09-06 01:36:12 UTC (rev 266677)
@@ -333,6 +333,8 @@
bool shouldUseTiledBackingForFrameView(const WebCore::FrameView&) const final;
+ MonotonicTime timestampForPaintFrequencyTracking() const final;
+
void isPlayingMediaDidChange(WebCore::MediaProducer::MediaStateFlags, uint64_t) final;
void handleAutoplayEvent(WebCore::AutoplayEvent, OptionSet<WebCore::AutoplayEventFlags>) final;