Title: [266677] trunk/Source
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;
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to