<!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>[198851] trunk/Source/WebInspectorUI</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/198851">198851</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2016-03-30 12:36:20 -0700 (Wed, 30 Mar 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>Web Inspector: Calculate more accurate time per-sample instead of assuming 1ms
https://bugs.webkit.org/show_bug.cgi?id=155961
&lt;rdar://problem/25404505&gt;

Patch by Joseph Pecoraro &lt;pecoraro@apple.com&gt; on 2016-03-30
Reviewed by Geoffrey Garen.

Give each sample a duration based on the best time bounds we have available.
Script Profiler Events give us time bounds for (nearly) all script evaluations.
The only evaluations that are missed are Inspector scripts.

The duration per-sample is computed per-event:

    durationPerSample = (event.endTime - event.startTime) / numSamplesInTimeRange.

If a 10ms Script Event contains 5 samples, they would each get a 2ms duration.
If a 0.5ms Script Event contains 1 sample, it would get a 0.5ms duration.

We were seeing an average of 1.6-1.8ms per sample for events that had more
than 3 samples.

* UserInterface/Controllers/TimelineManager.js:
(WebInspector.TimelineManager.prototype.scriptProfilerTrackingCompleted):
Associate a time duration per sample. For each Script Event we compute
an average time for all the samples in the event and assign it to the sample.

* UserInterface/Models/CallingContextTree.js:
(WebInspector.CallingContextTree.prototype.totalDurationInTimeRange):
(WebInspector.CallingContextTree.prototype.numberOfSamplesInTimeRange): Deleted.
Accumulate the duration by checking each sample. Number of samples
is now meaningless.

(WebInspector.CallingContextTree.prototype.updateTreeWithStackTrace):
(WebInspector.CCTNode):
(WebInspector.CCTNode.prototype.addTimestampAndExpressionLocation):
Give CCTNodes a list of durations and leafDurations that parallels
the timestamps and leafTimestamps lists of individual samples.

(WebInspector.CCTNode.prototype.filteredTimestampsAndDuration):
(WebInspector.CCTNode.prototype.filteredLeafTimestampsAndDuration):
(WebInspector.CCTNode.prototype.filteredTimestamps): Deleted.
(WebInspector.CCTNode.prototype.numberOfLeafTimestamps): Deleted.
Whenever we get a list of timestamps, also compute the duration
of those timestamps at the same time.

* UserInterface/Views/ProfileDataGridNode.js:
(WebInspector.ProfileDataGridNode):
(WebInspector.ProfileDataGridNode.prototype._updateChildrenForModifiers):
(WebInspector.ProfileDataGridNode.prototype._recalculateData):
* UserInterface/Views/ProfileDataGridTree.js:
(WebInspector.ProfileDataGridTree):
(WebInspector.ProfileDataGridTree.prototype.get totalSampleTime):
(WebInspector.ProfileDataGridTree.prototype._updateCurrentFocusDetails):
(WebInspector.ProfileDataGridTree.prototype.get sampleInterval): Deleted.
(WebInspector.ProfileDataGridTree.prototype.get numberOfSamples): Deleted.
Instead of computing total time from (samples * sampleInterval),
accumulate it by adding up the duration of each individual sample.
Update the Profile Data Grid nodes to use the new calculations.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebInspectorUIChangeLog">trunk/Source/WebInspectorUI/ChangeLog</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceControllersTimelineManagerjs">trunk/Source/WebInspectorUI/UserInterface/Controllers/TimelineManager.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceModelsCallingContextTreejs">trunk/Source/WebInspectorUI/UserInterface/Models/CallingContextTree.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsProfileDataGridNodejs">trunk/Source/WebInspectorUI/UserInterface/Views/ProfileDataGridNode.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsProfileDataGridTreejs">trunk/Source/WebInspectorUI/UserInterface/Views/ProfileDataGridTree.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebInspectorUIChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/ChangeLog (198850 => 198851)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/ChangeLog        2016-03-30 19:36:11 UTC (rev 198850)
+++ trunk/Source/WebInspectorUI/ChangeLog        2016-03-30 19:36:20 UTC (rev 198851)
</span><span class="lines">@@ -1,3 +1,63 @@
</span><ins>+2016-03-30  Joseph Pecoraro  &lt;pecoraro@apple.com&gt;
+
+        Web Inspector: Calculate more accurate time per-sample instead of assuming 1ms
+        https://bugs.webkit.org/show_bug.cgi?id=155961
+        &lt;rdar://problem/25404505&gt;
+
+        Reviewed by Geoffrey Garen.
+
+        Give each sample a duration based on the best time bounds we have available.
+        Script Profiler Events give us time bounds for (nearly) all script evaluations.
+        The only evaluations that are missed are Inspector scripts.
+
+        The duration per-sample is computed per-event:
+
+            durationPerSample = (event.endTime - event.startTime) / numSamplesInTimeRange.
+
+        If a 10ms Script Event contains 5 samples, they would each get a 2ms duration.
+        If a 0.5ms Script Event contains 1 sample, it would get a 0.5ms duration.
+
+        We were seeing an average of 1.6-1.8ms per sample for events that had more
+        than 3 samples.
+
+        * UserInterface/Controllers/TimelineManager.js:
+        (WebInspector.TimelineManager.prototype.scriptProfilerTrackingCompleted):
+        Associate a time duration per sample. For each Script Event we compute
+        an average time for all the samples in the event and assign it to the sample.
+
+        * UserInterface/Models/CallingContextTree.js:
+        (WebInspector.CallingContextTree.prototype.totalDurationInTimeRange):
+        (WebInspector.CallingContextTree.prototype.numberOfSamplesInTimeRange): Deleted.
+        Accumulate the duration by checking each sample. Number of samples
+        is now meaningless.
+        
+        (WebInspector.CallingContextTree.prototype.updateTreeWithStackTrace):
+        (WebInspector.CCTNode):
+        (WebInspector.CCTNode.prototype.addTimestampAndExpressionLocation):
+        Give CCTNodes a list of durations and leafDurations that parallels
+        the timestamps and leafTimestamps lists of individual samples.
+
+        (WebInspector.CCTNode.prototype.filteredTimestampsAndDuration):
+        (WebInspector.CCTNode.prototype.filteredLeafTimestampsAndDuration):
+        (WebInspector.CCTNode.prototype.filteredTimestamps): Deleted.
+        (WebInspector.CCTNode.prototype.numberOfLeafTimestamps): Deleted.
+        Whenever we get a list of timestamps, also compute the duration
+        of those timestamps at the same time.
+
+        * UserInterface/Views/ProfileDataGridNode.js:
+        (WebInspector.ProfileDataGridNode):
+        (WebInspector.ProfileDataGridNode.prototype._updateChildrenForModifiers):
+        (WebInspector.ProfileDataGridNode.prototype._recalculateData):
+        * UserInterface/Views/ProfileDataGridTree.js:
+        (WebInspector.ProfileDataGridTree):
+        (WebInspector.ProfileDataGridTree.prototype.get totalSampleTime):
+        (WebInspector.ProfileDataGridTree.prototype._updateCurrentFocusDetails):
+        (WebInspector.ProfileDataGridTree.prototype.get sampleInterval): Deleted.
+        (WebInspector.ProfileDataGridTree.prototype.get numberOfSamples): Deleted.
+        Instead of computing total time from (samples * sampleInterval),
+        accumulate it by adding up the duration of each individual sample.
+        Update the Profile Data Grid nodes to use the new calculations.
+
</ins><span class="cx"> 2016-03-29  Dana Burkart and Matthew Hanson  &lt;dburkart@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Web Inspector: JS PrettyPrinting in do/while loops, &quot;while&quot; should be on the same line as &quot;}&quot; if there was a closing brace
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceControllersTimelineManagerjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Controllers/TimelineManager.js (198850 => 198851)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Controllers/TimelineManager.js        2016-03-30 19:36:11 UTC (rev 198850)
+++ trunk/Source/WebInspectorUI/UserInterface/Controllers/TimelineManager.js        2016-03-30 19:36:20 UTC (rev 198851)
</span><span class="lines">@@ -773,17 +773,48 @@
</span><span class="cx">         console.assert(!this._webTimelineScriptRecordsExpectingScriptProfilerEvents || this._scriptProfilerRecords.length &gt;= this._webTimelineScriptRecordsExpectingScriptProfilerEvents.length);
</span><span class="cx"> 
</span><span class="cx">         if (samples) {
</span><del>-            // Associate the stackTraces with the ScriptProfiler created records.
</del><span class="cx">             let {totalTime: totalExecutionTime, stackTraces} = samples;
</span><span class="cx">             let topDownCallingContextTree = this.activeRecording.topDownCallingContextTree;
</span><span class="cx">             let bottomUpCallingContextTree = this.activeRecording.bottomUpCallingContextTree;
</span><span class="cx"> 
</span><ins>+            // Calculate a per-sample duration.
+            let timestampIndex = 0;
+            let timestampCount = stackTraces.length;
+            let sampleDurations = new Array(timestampCount);
+            let sampleDurationIndex = 0;
+            const defaultDuration = 1 / 1000; // 1ms.
+            for (let i = 0; i &lt; this._scriptProfilerRecords.length; ++i) {
+                let record = this._scriptProfilerRecords[i];
+
+                // Use a default duration for timestamps recorded outside of ScriptProfiler events.
+                while (timestampIndex &lt; timestampCount &amp;&amp; stackTraces[timestampIndex].timestamp &lt; record.startTime) {
+                    sampleDurations[sampleDurationIndex++] = defaultDuration;
+                    timestampIndex++;
+                }
+
+                // Average the duration per sample across all samples during the record.
+                let samplesInRecord = 0;
+                while (timestampIndex &lt; timestampCount &amp;&amp; stackTraces[timestampIndex].timestamp &lt; record.endTime) {
+                    timestampIndex++;
+                    samplesInRecord++;
+                }
+                if (samplesInRecord) {
+                    let averageDuration = (record.endTime - record.startTime) / samplesInRecord;
+                    sampleDurations.fill(averageDuration, sampleDurationIndex, sampleDurationIndex + samplesInRecord);
+                    sampleDurationIndex += samplesInRecord;
+                }
+            }
+
+            // Use a default duration for timestamps recorded outside of ScriptProfiler events.
+            if (timestampIndex &lt; timestampCount)
+                sampleDurations.fill(defaultDuration, sampleDurationIndex);
+
</ins><span class="cx">             topDownCallingContextTree.increaseExecutionTime(totalExecutionTime);
</span><span class="cx">             bottomUpCallingContextTree.increaseExecutionTime(totalExecutionTime);
</span><span class="cx"> 
</span><span class="cx">             for (let i = 0; i &lt; stackTraces.length; i++) {
</span><del>-                topDownCallingContextTree.updateTreeWithStackTrace(stackTraces[i]);
-                bottomUpCallingContextTree.updateTreeWithStackTrace(stackTraces[i]);
</del><ins>+                topDownCallingContextTree.updateTreeWithStackTrace(stackTraces[i], sampleDurations[i]);
+                bottomUpCallingContextTree.updateTreeWithStackTrace(stackTraces[i], sampleDurations[i]);
</ins><span class="cx">             }
</span><span class="cx"> 
</span><span class="cx">             // FIXME: This transformation should not be needed after introducing ProfileView.
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceModelsCallingContextTreejs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Models/CallingContextTree.js (198850 => 198851)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Models/CallingContextTree.js        2016-03-30 19:36:11 UTC (rev 198850)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/CallingContextTree.js        2016-03-30 19:36:20 UTC (rev 198851)
</span><span class="lines">@@ -47,9 +47,9 @@
</span><span class="cx">         this._totalNumberOfSamples = 0;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    numberOfSamplesInTimeRange(startTime, endTime)
</del><ins>+    totalDurationInTimeRange(startTime, endTime)
</ins><span class="cx">     {
</span><del>-        return this._root.filteredTimestamps(startTime, endTime).length;
</del><ins>+        return this._root.filteredTimestampsAndDuration(startTime, endTime).duration;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     increaseExecutionTime(executionTime)
</span><span class="lines">@@ -57,24 +57,24 @@
</span><span class="cx">         this._totalExecutionTime += executionTime;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    updateTreeWithStackTrace({timestamp, stackFrames})
</del><ins>+    updateTreeWithStackTrace({timestamp, stackFrames}, duration)
</ins><span class="cx">     {
</span><span class="cx">         this._totalNumberOfSamples++;
</span><span class="cx"> 
</span><span class="cx">         let node = this._root;
</span><del>-        node.addTimestampAndExpressionLocation(timestamp, null);
</del><ins>+        node.addTimestampAndExpressionLocation(timestamp, duration, null);
</ins><span class="cx"> 
</span><span class="cx">         if (this._type === WebInspector.CallingContextTree.Type.TopDown) {
</span><span class="cx">             for (let i = stackFrames.length; i--; ) {
</span><span class="cx">                 let stackFrame = stackFrames[i];
</span><span class="cx">                 node = node.findOrMakeChild(stackFrame);
</span><del>-                node.addTimestampAndExpressionLocation(timestamp, stackFrame.expressionLocation || null, i === 0);
</del><ins>+                node.addTimestampAndExpressionLocation(timestamp, duration, stackFrame.expressionLocation || null, i === 0);
</ins><span class="cx">             }
</span><span class="cx">         } else {
</span><span class="cx">             for (let i = 0; i &lt; stackFrames.length; ++i) {
</span><span class="cx">                 let stackFrame = stackFrames[i];
</span><span class="cx">                 node = node.findOrMakeChild(stackFrame);
</span><del>-                node.addTimestampAndExpressionLocation(timestamp, stackFrame.expressionLocation || null, i === 0);
</del><ins>+                node.addTimestampAndExpressionLocation(timestamp, duration, stackFrame.expressionLocation || null, i === 0);
</ins><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="lines">@@ -83,7 +83,7 @@
</span><span class="cx">     {
</span><span class="cx">         let cpuProfile = {};
</span><span class="cx">         let roots = [];
</span><del>-        let numSamplesInTimeRange = this.numberOfSamplesInTimeRange(startTime, endTime);
</del><ins>+        let numSamplesInTimeRange = this._root.filteredTimestampsAndDuration(startTime, endTime).timestamps.length;
</ins><span class="cx"> 
</span><span class="cx">         this._root.forEachChild((child) =&gt; {
</span><span class="cx">             if (child.hasStackTraceInTimeRange(startTime, endTime))
</span><span class="lines">@@ -164,7 +164,9 @@
</span><span class="cx">         this._uid = WebInspector.CCTNode.__uid++;
</span><span class="cx"> 
</span><span class="cx">         this._timestamps = [];
</span><ins>+        this._durations = [];
</ins><span class="cx">         this._leafTimestamps = [];
</span><ins>+        this._leafDurations = [];
</ins><span class="cx">         this._expressionLocations = {}; // Keys are &quot;line:column&quot; strings. Values are arrays of timestamps in sorted order.
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -214,32 +216,34 @@
</span><span class="cx">         return hasTimestampInRange;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    filteredTimestamps(startTime, endTime)
</del><ins>+    filteredTimestampsAndDuration(startTime, endTime)
</ins><span class="cx">     {
</span><del>-        let index = this._timestamps.lowerBound(startTime); // The left-most (smallest) item that is &gt;= startTime.
-        let result = [];
-        for (; index &lt; this._timestamps.length; index++) {
-            let timestamp = this._timestamps[index];
-            console.assert(startTime &lt;= timestamp);
-            if (!(timestamp &lt;= endTime))
-                break;
-            result.push(timestamp);
-        }
-        return result;
</del><ins>+        let lowerIndex = this._timestamps.lowerBound(startTime);
+        let upperIndex = this._timestamps.upperBound(endTime);
+
+        let totalDuration = 0;
+        for (let i = lowerIndex; i &lt; upperIndex; ++i)
+            totalDuration += this._durations[i];
+
+        return {
+            timestamps: this._timestamps.slice(lowerIndex, upperIndex),
+            duration: totalDuration,
+        };
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    numberOfLeafTimestamps(startTime, endTime)
</del><ins>+    filteredLeafTimestampsAndDuration(startTime, endTime)
</ins><span class="cx">     {
</span><del>-        let count = 0;
</del><span class="cx">         let lowerIndex = this._leafTimestamps.lowerBound(startTime);
</span><del>-        for (let i = lowerIndex; i &lt; this._leafTimestamps.length; ++i) {
-            let timestamp = this._leafTimestamps[i];
-            console.assert(startTime &lt;= timestamp);
-            if (!(timestamp &lt;= endTime))
-                break;
-            count++;
-        }
-        return count;
</del><ins>+        let upperIndex = this._leafTimestamps.upperBound(endTime);
+
+        let totalDuration = 0;
+        for (let i = lowerIndex; i &lt; upperIndex; ++i)
+            totalDuration += this._leafDurations[i];
+
+        return {
+            leafTimestamps: this._leafTimestamps.slice(lowerIndex, upperIndex),
+            leafDuration: totalDuration,
+        };
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     hasChildren()
</span><span class="lines">@@ -258,13 +262,16 @@
</span><span class="cx">         return node;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    addTimestampAndExpressionLocation(timestamp, expressionLocation, leaf)
</del><ins>+    addTimestampAndExpressionLocation(timestamp, duration, expressionLocation, leaf)
</ins><span class="cx">     {
</span><span class="cx">         console.assert(!this._timestamps.length || this._timestamps.lastValue &lt;= timestamp, &quot;Expected timestamps to be added in sorted, increasing, order.&quot;);
</span><span class="cx">         this._timestamps.push(timestamp);
</span><ins>+        this._durations.push(duration);
</ins><span class="cx"> 
</span><del>-        if (leaf)
</del><ins>+        if (leaf) {
</ins><span class="cx">             this._leafTimestamps.push(timestamp);
</span><ins>+            this._leafDurations.push(duration);
+        }
</ins><span class="cx"> 
</span><span class="cx">         if (!expressionLocation)
</span><span class="cx">             return;
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsProfileDataGridNodejs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ProfileDataGridNode.js (198850 => 198851)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/ProfileDataGridNode.js        2016-03-30 19:36:11 UTC (rev 198850)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ProfileDataGridNode.js        2016-03-30 19:36:20 UTC (rev 198851)
</span><span class="lines">@@ -34,6 +34,7 @@
</span><span class="cx"> 
</span><span class="cx">         this._populated = false;
</span><span class="cx">         this._childrenToChargeToSelf = new Set;
</span><ins>+        this._extraSelfTimeFromChargedChildren = 0;
</ins><span class="cx"> 
</span><span class="cx">         // FIXME: Make profile data grid nodes copyable.
</span><span class="cx">         this.copyable = false;
</span><span class="lines">@@ -159,9 +160,8 @@
</span><span class="cx">                 for (let {type, source} of this._tree.modifiers) {
</span><span class="cx">                     if (type === WebInspector.ProfileDataGridTree.ModifierType.ChargeToCaller) {
</span><span class="cx">                         if (child.equals(source)) {
</span><del>-                            this._childrenToChargeToSelf.add(child);
-                            let childSubtreeSamples = child.filteredTimestamps(this._tree.startTime, this._tree.endTime).length;
-                            this._extraSelfTimeFromChargedChildren += childSubtreeSamples * this._tree.sampleInterval;
</del><ins>+                            this._childrenToChargeToSelf.add(child);                            
+                            this._extraSelfTimeFromChargedChildren += child.filteredTimestampsAndDuration(this._tree.startTime, this._tree.endTime).duration;                            
</ins><span class="cx">                             continue;
</span><span class="cx">                         }
</span><span class="cx">                     }
</span><span class="lines">@@ -183,13 +183,12 @@
</span><span class="cx"> 
</span><span class="cx">     _recalculateData()
</span><span class="cx">     {
</span><del>-        let timestamps = this._node.filteredTimestamps(this._tree.startTime, this._tree.endTime);
-        let leafs = this._node.numberOfLeafTimestamps(this._tree.startTime, this._tree.endTime);
</del><ins>+        let {timestamps, duration} = this._node.filteredTimestampsAndDuration(this._tree.startTime, this._tree.endTime);
+        let {leafTimestamps, leafDuration} = this._node.filteredLeafTimestampsAndDuration(this._tree.startTime, this._tree.endTime);
</ins><span class="cx"> 
</span><del>-        let sampleInterval = this._tree.sampleInterval;
-        let totalTime = timestamps.length * sampleInterval;
-        let selfTime = (leafs * sampleInterval) + this._extraSelfTimeFromChargedChildren;
-        let percent = (totalTime / (this._tree.numberOfSamples * sampleInterval)) * 100;
</del><ins>+        let totalTime = duration;
+        let selfTime = leafDuration + this._extraSelfTimeFromChargedChildren;
+        let percent = (totalTime / this._tree.totalSampleTime) * 100;
</ins><span class="cx"> 
</span><span class="cx">         this._data = {totalTime, selfTime, percent};
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsProfileDataGridTreejs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ProfileDataGridTree.js (198850 => 198851)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/ProfileDataGridTree.js        2016-03-30 19:36:11 UTC (rev 198850)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ProfileDataGridTree.js        2016-03-30 19:36:20 UTC (rev 198851)
</span><span class="lines">@@ -38,7 +38,7 @@
</span><span class="cx">         this._callingContextTree = callingContextTree;
</span><span class="cx">         this._startTime = startTime;
</span><span class="cx">         this._endTime = endTime;
</span><del>-        this._numberOfSamples = this._callingContextTree.numberOfSamplesInTimeRange(startTime, endTime);
</del><ins>+        this._totalSampleTime = this._callingContextTree.totalDurationInTimeRange(startTime, endTime);
</ins><span class="cx"> 
</span><span class="cx">         this._focusNodes = [];
</span><span class="cx">         this._modifiers = [];
</span><span class="lines">@@ -61,15 +61,6 @@
</span><span class="cx"> 
</span><span class="cx">     get callingContextTree() { return this._callingContextTree; }
</span><span class="cx"> 
</span><del>-    get sampleInterval()
-    {
-        // FIXME: It would be good to bound this, but the startTime/endTime can be beyond the
-        // bounds of when the calling context tree was sampling. This could be improved when a
-        // subset within the timeline is selected (a better bounding start/end). For now just
-        // assume a constant rate, as that roughly matches what the intent is.
-        return 1 / 1000; // 1ms per sample
-    }
-
</del><span class="cx">     get focusNodes()
</span><span class="cx">     {
</span><span class="cx">         return this._focusNodes;
</span><span class="lines">@@ -99,11 +90,11 @@
</span><span class="cx">         return this._endTime;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    get numberOfSamples()
</del><ins>+    get totalSampleTime()
</ins><span class="cx">     {
</span><span class="cx">         if (this._focusNodes.length)
</span><del>-            return this._currentFocusNumberOfSamples;
-        return this._numberOfSamples;
</del><ins>+            return this._currentFocusTotalSampleTime;
+        return this._totalSampleTime;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     get children()
</span><span class="lines">@@ -249,11 +240,11 @@
</span><span class="cx">     _updateCurrentFocusDetails(focusDataGridNode)
</span><span class="cx">     {
</span><span class="cx">         let cctNode = focusDataGridNode.node;
</span><del>-        let timestampsInRange = cctNode.filteredTimestamps(this._startTime, this._endTime);
</del><ins>+        let {timestamps, duration} = cctNode.filteredTimestampsAndDuration(this._startTime, this._endTime);
</ins><span class="cx"> 
</span><del>-        this._currentFocusStartTime = timestampsInRange[0];
-        this._currentFocusEndTime = timestampsInRange.lastValue;
-        this._currentFocusNumberOfSamples = timestampsInRange.length;
</del><ins>+        this._currentFocusStartTime = timestamps[0];
+        this._currentFocusEndTime = timestamps.lastValue;
+        this._currentFocusTotalSampleTime = duration;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     _saveFocusedNodeOriginalParent(focusDataGridNode)
</span></span></pre>
</div>
</div>

</body>
</html>