<!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>[171616] 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/171616">171616</a></dd>
<dt>Author</dt> <dd>jer.noble@apple.com</dd>
<dt>Date</dt> <dd>2014-07-25 14:35:28 -0700 (Fri, 25 Jul 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>[MSE] High CPU usage in SampleMap::findSamplesWithinPresentationRange() with a large number of buffered samples.
https://bugs.webkit.org/show_bug.cgi?id=135247

Reviewed by Geoffrey Garen.

Anchor our search for overlapping frames to the end of the search range when the overlap range is sufficiently
close to the end of the search range. The common case for this search is when a sample is about to be appended
to the end of the sample queue, so this should turn most searches into no-ops.

* Modules/mediasource/SampleMap.cpp:
(WebCore::PresentationOrderSampleMap::findSamplesWithinPresentationRangeFromEnd):
* Modules/mediasource/SampleMap.h:
* Modules/mediasource/SourceBuffer.cpp:
(WebCore::SourceBuffer::sourceBufferPrivateDidReceiveSample):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreModulesmediasourceSampleMapcpp">trunk/Source/WebCore/Modules/mediasource/SampleMap.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesmediasourceSampleMaph">trunk/Source/WebCore/Modules/mediasource/SampleMap.h</a></li>
<li><a href="#trunkSourceWebCoreModulesmediasourceSourceBuffercpp">trunk/Source/WebCore/Modules/mediasource/SourceBuffer.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (171615 => 171616)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2014-07-25 21:31:07 UTC (rev 171615)
+++ trunk/Source/WebCore/ChangeLog        2014-07-25 21:35:28 UTC (rev 171616)
</span><span class="lines">@@ -1,3 +1,20 @@
</span><ins>+2014-07-25  Jer Noble  &lt;jer.noble@apple.com&gt;
+
+        [MSE] High CPU usage in SampleMap::findSamplesWithinPresentationRange() with a large number of buffered samples.
+        https://bugs.webkit.org/show_bug.cgi?id=135247
+
+        Reviewed by Geoffrey Garen.
+
+        Anchor our search for overlapping frames to the end of the search range when the overlap range is sufficiently
+        close to the end of the search range. The common case for this search is when a sample is about to be appended
+        to the end of the sample queue, so this should turn most searches into no-ops.
+
+        * Modules/mediasource/SampleMap.cpp:
+        (WebCore::PresentationOrderSampleMap::findSamplesWithinPresentationRangeFromEnd):
+        * Modules/mediasource/SampleMap.h:
+        * Modules/mediasource/SourceBuffer.cpp:
+        (WebCore::SourceBuffer::sourceBufferPrivateDidReceiveSample):
+
</ins><span class="cx"> 2014-07-25  Gavin Barraclough  &lt;baraclough@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Yosemite version number is 101000
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesmediasourceSampleMapcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/mediasource/SampleMap.cpp (171615 => 171616)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/mediasource/SampleMap.cpp        2014-07-25 21:31:07 UTC (rev 171615)
+++ trunk/Source/WebCore/Modules/mediasource/SampleMap.cpp        2014-07-25 21:35:28 UTC (rev 171616)
</span><span class="lines">@@ -238,6 +238,19 @@
</span><span class="cx">     return std::equal_range(begin(), end(), range, SamplePresentationTimeIsWithinRangeComparator());
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+PresentationOrderSampleMap::iterator_range PresentationOrderSampleMap::findSamplesWithinPresentationRangeFromEnd(const MediaTime&amp; beginTime, const MediaTime&amp; endTime)
+{
+    reverse_iterator rangeEnd = std::find_if(rbegin(), rend(), [&amp;beginTime] (PresentationOrderSampleMap::MapType::value_type value) {
+        return value.second-&gt;presentationTime() &lt;= beginTime;
+    });
+
+    reverse_iterator rangeStart = std::find_if(rbegin(), rangeEnd, [&amp;endTime] (PresentationOrderSampleMap::MapType::value_type value) {
+        return value.second-&gt;presentationTime() &lt;= endTime;
+    });
+
+    return iterator_range(rangeStart.base(), rangeEnd.base());
+}
+
</ins><span class="cx"> DecodeOrderSampleMap::reverse_iterator_range DecodeOrderSampleMap::findDependentSamples(MediaSample* sample)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(sample);
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesmediasourceSampleMaph"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/mediasource/SampleMap.h (171615 => 171616)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/mediasource/SampleMap.h        2014-07-25 21:31:07 UTC (rev 171615)
+++ trunk/Source/WebCore/Modules/mediasource/SampleMap.h        2014-07-25 21:35:28 UTC (rev 171616)
</span><span class="lines">@@ -57,6 +57,7 @@
</span><span class="cx">     reverse_iterator reverseFindSampleBeforePresentationTime(const MediaTime&amp;);
</span><span class="cx">     iterator_range findSamplesBetweenPresentationTimes(const MediaTime&amp;, const MediaTime&amp;);
</span><span class="cx">     iterator_range findSamplesWithinPresentationRange(const MediaTime&amp;, const MediaTime&amp;);
</span><ins>+    iterator_range findSamplesWithinPresentationRangeFromEnd(const MediaTime&amp;, const MediaTime&amp;);
</ins><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     MapType m_samples;
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesmediasourceSourceBuffercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/mediasource/SourceBuffer.cpp (171615 => 171616)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/mediasource/SourceBuffer.cpp        2014-07-25 21:31:07 UTC (rev 171615)
+++ trunk/Source/WebCore/Modules/mediasource/SourceBuffer.cpp        2014-07-25 21:35:28 UTC (rev 171616)
</span><span class="lines">@@ -1145,9 +1145,29 @@
</span><span class="cx">         if (trackBuffer.highestPresentationTimestamp.isValid() &amp;&amp; trackBuffer.highestPresentationTimestamp &lt;= presentationTimestamp) {
</span><span class="cx">             // Remove all coded frames from track buffer that have a presentation timestamp greater than highest
</span><span class="cx">             // presentation timestamp and less than or equal to frame end timestamp.
</span><del>-            auto iter_pair = trackBuffer.samples.presentationOrder().findSamplesWithinPresentationRange(trackBuffer.highestPresentationTimestamp, frameEndTimestamp);
-            if (iter_pair.first != trackBuffer.samples.presentationOrder().end())
-                erasedSamples.addRange(iter_pair.first, iter_pair.second);
</del><ins>+            do {
+                // NOTE: Searching from the end of the trackBuffer will be vastly more efficient if the search range is
+                // near the end of the buffered range. Use a linear-backwards search if the search range is within one
+                // frame duration of the end:
+                if (!m_buffered)
+                    break;
+
+                unsigned bufferedLength = m_buffered-&gt;ranges().length();
+                if (!bufferedLength)
+                    break;
+
+                bool ignoreValid;
+                MediaTime highestBufferedTime = m_buffered-&gt;ranges().end(bufferedLength - 1, ignoreValid);
+
+                PresentationOrderSampleMap::iterator_range range;
+                if (highestBufferedTime - trackBuffer.highestPresentationTimestamp &lt; trackBuffer.lastFrameDuration)
+                    range = trackBuffer.samples.presentationOrder().findSamplesWithinPresentationRangeFromEnd(trackBuffer.highestPresentationTimestamp, frameEndTimestamp);
+                else
+                    range = trackBuffer.samples.presentationOrder().findSamplesWithinPresentationRange(trackBuffer.highestPresentationTimestamp, frameEndTimestamp);
+
+                if (range.first != trackBuffer.samples.presentationOrder().end())
+                    erasedSamples.addRange(range.first, range.second);
+            } while(false);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         // 1.16 Remove decoding dependencies of the coded frames removed in the previous step:
</span></span></pre>
</div>
</div>

</body>
</html>