<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[183194] trunk/Source/WebCore</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/183194">183194</a></dd>
<dt>Author</dt> <dd>antti@apple.com</dd>
<dt>Date</dt> <dd>2015-04-23 10:48:37 -0700 (Thu, 23 Apr 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>Memory cache live resources repeatedly purged during painting
https://bugs.webkit.org/show_bug.cgi?id=144104
&lt;rdar://problem/20667695&gt;

Reviewed by Chris Dumez.

On some PLT pages (like nytimes.com) we get into state where painting repeatedly purges live bitmaps.
This slows down page loads significantly.

This might have regressed because improvements in page caching keep more pages and so resources 'live'.

With this path we do all regular cache pruning asynchronously. If memory is really critical
the low memory handling code will still prune synchronously.

* loader/cache/CachedResource.cpp:
(WebCore::CachedResource::removeClient):
(WebCore::CachedResource::didAccessDecodedData):

    prune() -&gt; pruneSoon()

* loader/cache/MemoryCache.cpp:

    Decrease the pruning size target from 0.95 to 0.8 so we don't need to prune so often.

(WebCore::MemoryCache::needsPruning):

    Factor into a function.

(WebCore::MemoryCache::prune):
(WebCore::MemoryCache::pruneSoon):

    Prune asynchronously.

* loader/cache/MemoryCache.h:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreloadercacheCachedResourcecpp">trunk/Source/WebCore/loader/cache/CachedResource.cpp</a></li>
<li><a href="#trunkSourceWebCoreloadercacheMemoryCachecpp">trunk/Source/WebCore/loader/cache/MemoryCache.cpp</a></li>
<li><a href="#trunkSourceWebCoreloadercacheMemoryCacheh">trunk/Source/WebCore/loader/cache/MemoryCache.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (183193 => 183194)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2015-04-23 17:31:30 UTC (rev 183193)
+++ trunk/Source/WebCore/ChangeLog        2015-04-23 17:48:37 UTC (rev 183194)
</span><span class="lines">@@ -1,3 +1,40 @@
</span><ins>+2015-04-23  Antti Koivisto  &lt;antti@apple.com&gt;
+
+        Memory cache live resources repeatedly purged during painting
+        https://bugs.webkit.org/show_bug.cgi?id=144104
+        &lt;rdar://problem/20667695&gt;
+
+        Reviewed by Chris Dumez.
+
+        On some PLT pages (like nytimes.com) we get into state where painting repeatedly purges live bitmaps.
+        This slows down page loads significantly.
+
+        This might have regressed because improvements in page caching keep more pages and so resources 'live'.
+
+        With this path we do all regular cache pruning asynchronously. If memory is really critical
+        the low memory handling code will still prune synchronously.
+
+        * loader/cache/CachedResource.cpp:
+        (WebCore::CachedResource::removeClient):
+        (WebCore::CachedResource::didAccessDecodedData):
+
+            prune() -&gt; pruneSoon()
+
+        * loader/cache/MemoryCache.cpp:
+
+            Decrease the pruning size target from 0.95 to 0.8 so we don't need to prune so often.
+
+        (WebCore::MemoryCache::needsPruning):
+
+            Factor into a function.
+
+        (WebCore::MemoryCache::prune):
+        (WebCore::MemoryCache::pruneSoon):
+
+            Prune asynchronously.
+
+        * loader/cache/MemoryCache.h:
+
</ins><span class="cx"> 2015-04-23  Eric Carlson  &lt;eric.carlson@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Unreviewed, make a suggested change I overlooked in Darin's review of
</span></span></pre></div>
<a id="trunkSourceWebCoreloadercacheCachedResourcecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/loader/cache/CachedResource.cpp (183193 => 183194)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/loader/cache/CachedResource.cpp        2015-04-23 17:31:30 UTC (rev 183193)
+++ trunk/Source/WebCore/loader/cache/CachedResource.cpp        2015-04-23 17:48:37 UTC (rev 183194)
</span><span class="lines">@@ -460,7 +460,7 @@
</span><span class="cx">             // We allow non-secure content to be reused in history, but we do not allow secure content to be reused.
</span><span class="cx">             memoryCache.remove(*this);
</span><span class="cx">         }
</span><del>-        memoryCache.prune();
</del><ins>+        memoryCache.pruneSoon();
</ins><span class="cx">     }
</span><span class="cx">     // This object may be dead here.
</span><span class="cx"> }
</span><span class="lines">@@ -557,7 +557,7 @@
</span><span class="cx">             memoryCache.removeFromLiveDecodedResourcesList(*this);
</span><span class="cx">             memoryCache.insertInLiveDecodedResourcesList(*this);
</span><span class="cx">         }
</span><del>-        memoryCache.prune();
</del><ins>+        memoryCache.pruneSoon();
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx">     
</span></span></pre></div>
<a id="trunkSourceWebCoreloadercacheMemoryCachecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/loader/cache/MemoryCache.cpp (183193 => 183194)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/loader/cache/MemoryCache.cpp        2015-04-23 17:31:30 UTC (rev 183193)
+++ trunk/Source/WebCore/loader/cache/MemoryCache.cpp        2015-04-23 17:48:37 UTC (rev 183194)
</span><span class="lines">@@ -43,6 +43,7 @@
</span><span class="cx"> #include &lt;wtf/CurrentTime.h&gt;
</span><span class="cx"> #include &lt;wtf/MathExtras.h&gt;
</span><span class="cx"> #include &lt;wtf/NeverDestroyed.h&gt;
</span><ins>+#include &lt;wtf/RunLoop.h&gt;
</ins><span class="cx"> #include &lt;wtf/TemporaryChange.h&gt;
</span><span class="cx"> #include &lt;wtf/text/CString.h&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -50,7 +51,7 @@
</span><span class="cx"> 
</span><span class="cx"> static const int cDefaultCacheCapacity = 8192 * 1024;
</span><span class="cx"> static const double cMinDelayBeforeLiveDecodedPrune = 1; // Seconds.
</span><del>-static const float cTargetPrunePercentage = .95f; // Percentage of capacity toward which we prune, to avoid immediately pruning again.
</del><ins>+static const float cTargetPrunePercentage = 0.8; // Percentage of capacity toward which we prune, to avoid immediately pruning again.
</ins><span class="cx"> static const auto defaultDecodedDataDeletionInterval = std::chrono::seconds { 0 };
</span><span class="cx"> 
</span><span class="cx"> MemoryCache&amp; MemoryCache::singleton()
</span><span class="lines">@@ -745,15 +746,34 @@
</span><span class="cx">     ASSERT(!m_sessionResources.contains(sessionID));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool MemoryCache::needsPruning() const
+{
+    return m_liveSize + m_deadSize &gt; m_capacity || m_deadSize &gt; m_maxDeadCapacity;
+}
+
</ins><span class="cx"> void MemoryCache::prune()
</span><span class="cx"> {
</span><del>-    if (m_liveSize + m_deadSize &lt;= m_capacity &amp;&amp; m_deadSize &lt;= m_maxDeadCapacity) // Fast path.
</del><ins>+    if (!needsPruning())
</ins><span class="cx">         return;
</span><del>-        
</del><ins>+
</ins><span class="cx">     pruneDeadResources(); // Prune dead first, in case it was &quot;borrowing&quot; capacity from live.
</span><span class="cx">     pruneLiveResources();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void MemoryCache::pruneSoon()
+{
+    if (m_willPruneSoon)
+        return;
+    if (!needsPruning())
+        return;
+
+    m_willPruneSoon = true;
+    RunLoop::main().dispatch([this] {
+        prune();
+        m_willPruneSoon = false;
+    });
+}
+
</ins><span class="cx"> #ifndef NDEBUG
</span><span class="cx"> void MemoryCache::dumpStats()
</span><span class="cx"> {
</span></span></pre></div>
<a id="trunkSourceWebCoreloadercacheMemoryCacheh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/loader/cache/MemoryCache.h (183193 => 183194)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/loader/cache/MemoryCache.h        2015-04-23 17:31:30 UTC (rev 183193)
+++ trunk/Source/WebCore/loader/cache/MemoryCache.h        2015-04-23 17:48:37 UTC (rev 183194)
</span><span class="lines">@@ -115,8 +115,9 @@
</span><span class="cx"> 
</span><span class="cx">     WEBCORE_EXPORT void evictResources();
</span><span class="cx">     WEBCORE_EXPORT void evictResources(SessionID);
</span><del>-    
</del><ins>+
</ins><span class="cx">     void prune();
</span><ins>+    void pruneSoon();
</ins><span class="cx">     unsigned size() const { return m_liveSize + m_deadSize; }
</span><span class="cx"> 
</span><span class="cx">     void setDeadDecodedDataDeletionInterval(std::chrono::milliseconds interval) { m_deadDecodedDataDeletionInterval = interval; }
</span><span class="lines">@@ -184,6 +185,7 @@
</span><span class="cx"> 
</span><span class="cx">     unsigned liveCapacity() const;
</span><span class="cx">     unsigned deadCapacity() const;
</span><ins>+    bool needsPruning() const;
</ins><span class="cx"> 
</span><span class="cx">     CachedResource* resourceForRequestImpl(const ResourceRequest&amp;, CachedResourceMap&amp;);
</span><span class="cx"> 
</span><span class="lines">@@ -213,6 +215,8 @@
</span><span class="cx">     // referenced by a Web page).
</span><span class="cx">     typedef HashMap&lt;SessionID, std::unique_ptr&lt;CachedResourceMap&gt;&gt; SessionCachedResourceMap;
</span><span class="cx">     SessionCachedResourceMap m_sessionResources;
</span><ins>+
+    bool m_willPruneSoon { false };
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> }
</span></span></pre>
</div>
</div>

</body>
</html>