<!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>[173381] trunk/Tools</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/173381">173381</a></dd>
<dt>Author</dt> <dd>ap@apple.com</dd>
<dt>Date</dt> <dd>2014-09-08 10:05:10 -0700 (Mon, 08 Sep 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>Dashboard metrics should ignore commits that didn't trigger builds
https://bugs.webkit.org/show_bug.cgi?id=136618

Reviewed by Darin Adler.

Commits that didn't trigger builds are ones like ChangeLog updates, patches for
other platforms etc. It does not make sense to count wait time for these, as it
can be arbitrarily long.

The new algorithm is much slower asymptotically, but it's OK, computers are fast.

* BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/BuildbotIteration.js:
(BuildbotIteration.prototype._parseData): Record changes that triggered the iteration.

* BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/MetricsAnalyzer.js:
We used to walk the timeline to see which revisions are fully tested, but that's not
correct. A revision that's only tested by a subset of queues finishes independently
of another that's tested by another subset. Now, we just search for the answer for
each revision individually.

* BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/MetricsView.js:
(MetricsView.prototype._update.appendQueueResults): Added worst revision number, which
the analyzer now reports. Removed best time, which is more confusing than meaningful.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkToolsBuildSlaveSupportbuildwebkitorgconfigpublic_htmldashboardScriptsBuildbotIterationjs">trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/BuildbotIteration.js</a></li>
<li><a href="#trunkToolsBuildSlaveSupportbuildwebkitorgconfigpublic_htmldashboardScriptsMetricsAnalyzerjs">trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/MetricsAnalyzer.js</a></li>
<li><a href="#trunkToolsBuildSlaveSupportbuildwebkitorgconfigpublic_htmldashboardScriptsMetricsViewjs">trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/MetricsView.js</a></li>
<li><a href="#trunkToolsChangeLog">trunk/Tools/ChangeLog</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkToolsBuildSlaveSupportbuildwebkitorgconfigpublic_htmldashboardScriptsBuildbotIterationjs"></a>
<div class="modfile"><h4>Modified: trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/BuildbotIteration.js (173380 => 173381)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/BuildbotIteration.js        2014-09-08 16:11:51 UTC (rev 173380)
+++ trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/BuildbotIteration.js        2014-09-08 17:05:10 UTC (rev 173381)
</span><span class="lines">@@ -258,6 +258,29 @@
</span><span class="cx">         var internalRevisionProperty = data.properties.findFirst(function(property) { return property[0] === &quot;internal_got_revision&quot; || isMultiCodebaseGotRevisionProperty(property); });
</span><span class="cx">         this.internalRevision = parseRevisionProperty(internalRevisionProperty, &quot;Internal&quot;);
</span><span class="cx"> 
</span><ins>+        function sourceStampChanges(sourceStamp) {
+            var result = [];
+            var changes = sourceStamp.changes;
+            for (var i = 0; i &lt; changes.length; ++i) {
+                var change = { revisionNumber: parseInt(changes[i].revision, 10) }
+                if (changes[i].repository)
+                    change.repository = changes[i].repository;
+                if (changes[i].branch)
+                    change.branch = changes[i].branch;
+                // There is also a timestamp, but it's not accurate.
+                result.push(change);
+            }
+            return result;
+        }
+
+        // The changes array is generally meaningful for svn triggered queues (such as builders),
+        // but not for internally triggered ones (such as testers), due to coalescing.
+        this.changes = [];
+        if (data.sourceStamp)
+            this.changes = sourceStampChanges(data.sourceStamp);
+        else for (var i = 0; i &lt; data.sourceStamps.length; ++i)
+            this.changes = this.changes.concat(sourceStampChanges(data.sourceStamps[i]));
+
</ins><span class="cx">         this.startTime = new Date(data.times[0] * 1000);
</span><span class="cx">         this.endTime = new Date(data.times[1] * 1000);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkToolsBuildSlaveSupportbuildwebkitorgconfigpublic_htmldashboardScriptsMetricsAnalyzerjs"></a>
<div class="modfile"><h4>Modified: trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/MetricsAnalyzer.js (173380 => 173381)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/MetricsAnalyzer.js        2014-09-08 16:11:51 UTC (rev 173380)
+++ trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/MetricsAnalyzer.js        2014-09-08 17:05:10 UTC (rev 173381)
</span><span class="lines">@@ -54,11 +54,19 @@
</span><span class="cx"> 
</span><span class="cx">         this._hasTracData = false;
</span><span class="cx"> 
</span><del>-        this._queues = queues;
</del><ins>+        // A commit can start a build-test sequence, or it can be ignored following builder queue rules.
+        // Only the builder queue knows which commits triggered builds, and which were ignored.
+        // We need to know which commits were ignored when measuring tester queue performance,
+        // so we load and analyze builder queues first.
+        this._queues = queues.slice(0);
+        this._queues.sort(function(a, b) { return b.builder - a.builder; });
+
</ins><span class="cx">         this._remainingQueues = {};
</span><span class="cx">         this._queuesReadyToAnalyze = [];
</span><span class="cx"> 
</span><del>-        queues.forEach(function(queue) {
</del><ins>+        this._triggeringCommitsByTriggeringQueue = {};
+
+        this._queues.forEach(function(queue) {
</ins><span class="cx">             if (!queue.iterations.length) {
</span><span class="cx">                 this._remainingQueues[queue.id] = queue;
</span><span class="cx">                 if (!this._queueBeingLoaded) {
</span><span class="lines">@@ -67,11 +75,41 @@
</span><span class="cx">                 }
</span><span class="cx">             } else
</span><span class="cx">                 this._queuesReadyToAnalyze.push(queue);
</span><del>-        }.bind(this));
</del><ins>+        }, this);
</ins><span class="cx"> 
</span><span class="cx">         webkitTrac.load(this._rangeStartTime, this._rangeEndTime);
</span><span class="cx">     },
</span><span class="cx"> 
</span><ins>+    _triggeringQueue: function(queue)
+    {
+        if (queue.builder)
+            return queue;
+        for (var i = 0; i &lt; this._queues.length; ++i) {
+            if (this._queues[i].tester)
+                continue;
+            if (this._queues[i].platform === queue.platform &amp;&amp; this._queues[i].architecture === queue.architecture &amp;&amp; this._queues[i].debug === queue.debug)
+                return this._queues[i];
+        }
+        // Efl bot both builds and tests, but is registered as tester.
+        return queue;
+    },
+
+    _recordTriggeringCommitsForTriggeringQueue: function(queue)
+    {
+        console.assert(!(queue.id in this._triggeringCommitsByTriggeringQueue));
+        console.assert(queue.id === this._triggeringQueue(queue).id);
+
+        var commits = {};
+        queue.iterations.forEach(function(iteration) {
+            iteration.changes.forEach(function(change) {
+                // FIXME: Support multiple source trees.
+                commits[change.revisionNumber] = 1;
+            });
+        });
+
+        this._triggeringCommitsByTriggeringQueue[queue.id] = commits;
+    },
+
</ins><span class="cx">     // Iterations is an array of finished iterations ordered by time, iterations[0] being the newest.
</span><span class="cx">     // Returns an index of an iteration that defined the queue color at the start, or -1
</span><span class="cx">     // if there was none.
</span><span class="lines">@@ -144,7 +182,7 @@
</span><span class="cx">                 var i = queueIterations.length - 1;
</span><span class="cx">             while (i &gt;= 0 &amp;&amp; queueIterations[i].endTime &lt;= this._rangeEndTime)
</span><span class="cx">                 iterations.push(queueIterations[i--]);
</span><del>-        }.bind(this));
</del><ins>+        }, this);
</ins><span class="cx"> 
</span><span class="cx">         iterations.sort(function(a, b) { return b.endTime - a.endTime; });
</span><span class="cx"> 
</span><span class="lines">@@ -207,102 +245,75 @@
</span><span class="cx">         }
</span><span class="cx">     },
</span><span class="cx"> 
</span><del>-    _fullyTestedRevisionNumber: function(lastTestedRevisionByQueue)
-    {
-        var result = Infinity;
-        this._queues.forEach(function(queue) {
-            if (lastTestedRevisionByQueue[queue.id] &lt; result)
-                result = lastTestedRevisionByQueue[queue.id];
-        });
-        return result;
-    },
-
</del><span class="cx">     _countTimes: function(queues, result)
</span><span class="cx">     {
</span><del>-        // Combine all iterations that started and finished within the range into one array.
-        // These are the iterations that can have results for revisions in the range.
-        var iterationsByRevision = [];
</del><ins>+        var relevantIterationsByQueue = {};
</ins><span class="cx">         queues.forEach(function(queue) {
</span><del>-            iterationsByRevision = iterationsByRevision.concat(queue.iterations.filter(function(iteration) {
</del><ins>+            relevantIterationsByQueue[queue.id] = queue.iterations.filter(function(iteration) {
</ins><span class="cx">                 return iteration.productive &amp;&amp; iteration.startTime &gt; this._rangeStartTime &amp;&amp; iteration.endTime &lt; this._rangeEndTime;
</span><del>-            }.bind(this)));
-        }.bind(this));
-        iterationsByRevision.sort(function(a, b) { return a.endTime - b.endTime; }); // When there are multiple iterations building the same revision, the first one wins (as the other ones were probably manual retries).
-        iterationsByRevision.sort(function(a, b) { return a.openSourceRevision - b.openSourceRevision; });
</del><ins>+            }, this);
+            relevantIterationsByQueue[queue.id].sort(function(a, b) { return a.endTime - b.endTime; });
+        }, this);
</ins><span class="cx"> 
</span><del>-        // Revisions that landed within the time range.
-        var revisions = webkitTrac.recordedCommits.reduce(function(result, revision) {
-            if (revision.date &gt;= this._rangeStartTime &amp;&amp; revision.date &lt; this._rangeEndTime)
-                result[revision.revisionNumber] = revision;
-            return result;
-        }.bind(this), {});
</del><ins>+        var times = [];
+        var ownTimes = [];
+        var worstTime = 0;
+        var worstOwnTime = 0
+        var worstTimeRevision;
+        var worstOwnTimeRevision;
</ins><span class="cx"> 
</span><del>-        // Find the oldest iteration for each queue. Revisions landed before a new bot was added are considered fully tested
-        // even without results from the not yet existent bot.
-        // Unfortunately, we don't know when the bot got added to dashboard, so we have to assume that it was there for as long as it had results.
-        var lastTestedRevisionByQueue = {};
-        queues.forEach(function(queue) {
-            var queueIterations = queue.iterations.filter(function(iteration) { return iteration.finished; });
-            queueIterations.sort(function(a, b) { return b.endTime - a.endTime; });
-            if (queueIterations.length &gt; 0)
-                lastTestedRevisionByQueue[queue.id] = queueIterations[queueIterations.length - 1].openSourceRevision;
-        });
</del><ins>+        webkitTrac.recordedCommits.forEach(function(revision) {
+            if (revision.date &lt; this._rangeStartTime || revision.date &gt;= this._rangeEndTime)
+                return;
</ins><span class="cx"> 
</span><del>-        var previousFullyTestedRevisionNumber = -1;
-
-        for (var i = 0; i &lt; iterationsByRevision.length; ++i) {
-            var iteration = iterationsByRevision[i];
-
-            console.assert(lastTestedRevisionByQueue[iteration.queue.id] === undefined || lastTestedRevisionByQueue[iteration.queue.id] &lt;= iteration.openSourceRevision);
-            lastTestedRevisionByQueue[iteration.queue.id] = iteration.openSourceRevision;
-
-            var newFullyTestedRevisionNumber = this._fullyTestedRevisionNumber(lastTestedRevisionByQueue);
-            console.assert(newFullyTestedRevisionNumber &gt;= previousFullyTestedRevisionNumber);
-
-            if (newFullyTestedRevisionNumber === previousFullyTestedRevisionNumber)
-                continue;
-
-            for (var revisionNumber = newFullyTestedRevisionNumber; (revisionNumber &gt; previousFullyTestedRevisionNumber) &amp;&amp; (revisionNumber in revisions); --revisionNumber) {
-                var revision = revisions[revisionNumber];
-                console.assert(!(&quot;elapsedTime&quot; in revision));
-                revision.elapsedTime = iteration.endTime - revision.date;
-                revision.elapsedOwnTime = iteration.endTime - iteration.startTime;
</del><ins>+            var endTime = -1;
+            var ownTime = -1;
+            queues.forEach(function(queue) {
+                if (!(revision.revisionNumber in this._triggeringCommitsByTriggeringQueue[this._triggeringQueue(queue).id]))
+                    return;
+                for (var i = 0; i &lt; relevantIterationsByQueue[queue.id].length; ++i) {
+                    var iteration = relevantIterationsByQueue[queue.id][i];
+                    if (iteration.openSourceRevision &gt;= revision.revisionNumber) {
+                        endTime = Math.max(endTime, iteration.endTime);
+                        ownTime = Math.max(ownTime, iteration.endTime - iteration.startTime);
+                        break;
+                    }
+                }
+            }, this);
+            if (endTime &gt;= 0) {
+                console.assert(ownTime &gt;= 0);
+                var time = endTime - revision.date;
+                times.push(time);
+                ownTimes.push(ownTime);
+                if (time &gt; worstTime) {
+                    worstTime = time;
+                    worstTimeCommit = revision.revisionNumber;
+                }
+                if (ownTime &gt; worstOwnTime) {
+                    worstOwnTime = ownTime;
+                    worstOwnTimeCommit = revision.revisionNumber;
+                }
</ins><span class="cx">             }
</span><ins>+        }, this);
</ins><span class="cx"> 
</span><del>-            previousFullyTestedRevisionNumber = newFullyTestedRevisionNumber;
-        }
-
-        var times = [];
-        var ownTimes = [];
-        for (var revisionNumber in revisions) {
-            var revision = revisions[revisionNumber];
-            if (!(&quot;elapsedTime&quot; in revision)) {
-                // A revision that landed within the time range didn't necessarily get all results by the range end.
-                continue;
-            }
-            // Changes on other branches are irrelevant, as they are not built or tested.
-            // FIXME: Support metrics for non-trunk queues.
-            if (!revision.containsBranchLocation || revision.branch === &quot;trunk&quot;) {
-                times.push(revision.elapsedTime);
-                ownTimes.push(revision.elapsedOwnTime);
-            }
-            delete revision.elapsedTime;
-            delete revision.elapsedOwnTime;
-        }
-
</del><span class="cx">         result.averageSecondsFromCommit = times.average() / 1000;
</span><span class="cx">         result.medianSecondsFromCommit = times.median() / 1000;
</span><del>-        result.bestSecondsFromCommit = Math.min.apply(Math, times) / 1000;
-        result.worstSecondsFromCommit = Math.max.apply(Math, times) / 1000;
</del><ins>+        console.assert(worstTime === Math.max.apply(Math, times));
+        result.worstSecondsFromCommit = worstTime / 1000;
+        result.revisionWithWorstTimeFromCommit = worstTimeCommit;
</ins><span class="cx"> 
</span><span class="cx">         result.averageSecondsOwnTime = ownTimes.average() / 1000;
</span><span class="cx">         result.medianSecondsOwnTime = ownTimes.median() / 1000;
</span><del>-        result.bestSecondsOwnTime = Math.min.apply(Math, ownTimes) / 1000;
-        result.worstSecondsOwnTime = Math.max.apply(Math, ownTimes) / 1000;
</del><ins>+        result.worstSecondsOwnTime = worstOwnTime / 1000;
+        console.assert(worstOwnTime === Math.max.apply(Math, ownTimes));
+        result.revisionWithWorstOwnTime = worstOwnTimeCommit;
</ins><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     _analyzeQueue: function(queue)
</span><span class="cx">     {
</span><ins>+        if (this._triggeringQueue(queue).id === queue.id &amp;&amp; !(queue.id in this._triggeringCommitsByTriggeringQueue))
+            this._recordTriggeringCommitsForTriggeringQueue(queue);
+
</ins><span class="cx">         var result = { queueID: queue.id };
</span><span class="cx">         this._countPercentageOfGreen([queue], result);
</span><span class="cx">         this._countTimes([queue], result);
</span><span class="lines">@@ -331,7 +342,7 @@
</span><span class="cx"> 
</span><span class="cx">         this._queuesReadyToAnalyze.forEach(function(queue) {
</span><span class="cx">             this._analyzeQueue(queue);
</span><del>-        }.bind(this));
</del><ins>+        }, this);
</ins><span class="cx"> 
</span><span class="cx">         this._queuesReadyToAnalyze = [];
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkToolsBuildSlaveSupportbuildwebkitorgconfigpublic_htmldashboardScriptsMetricsViewjs"></a>
<div class="modfile"><h4>Modified: trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/MetricsView.js (173380 => 173381)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/MetricsView.js        2014-09-08 16:11:51 UTC (rev 173380)
+++ trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/MetricsView.js        2014-09-08 17:05:10 UTC (rev 173381)
</span><span class="lines">@@ -122,15 +122,13 @@
</span><span class="cx">                 addLine(this.element, &quot;Time from commit: &quot;);
</span><span class="cx">                 addLine(this.element, &quot;Average: &quot; + Math.round(result.averageSecondsFromCommit / 60) + &quot; minutes&quot;);
</span><span class="cx">                 addLine(this.element, &quot;Median: &quot; + Math.round(result.medianSecondsFromCommit / 60) + &quot; minutes&quot;);
</span><del>-                addLine(this.element, &quot;Best: &quot; + Math.round(result.bestSecondsFromCommit / 60) + &quot; minutes&quot;);
-                addLine(this.element, &quot;Worst: &quot; + Math.round(result.worstSecondsFromCommit / 60) + &quot; minutes&quot;);
</del><ins>+                addLine(this.element, &quot;Worst: &quot; + Math.round(result.worstSecondsFromCommit / 60) + &quot; minutes (r&quot; + result.revisionWithWorstTimeFromCommit + &quot;)&quot;);
</ins><span class="cx">             } else {
</span><span class="cx">                 // Time from commit is pretty useless for tester bots.
</span><span class="cx">                 addLine(this.element, &quot;Time on the bot: &quot;);
</span><span class="cx">                 addLine(this.element, &quot;Average: &quot; + Math.round(result.averageSecondsOwnTime / 60) + &quot; minutes&quot;);
</span><span class="cx">                 addLine(this.element, &quot;Median: &quot; + Math.round(result.medianSecondsOwnTime / 60) + &quot; minutes&quot;);
</span><del>-                addLine(this.element, &quot;Best: &quot; + Math.round(result.bestSecondsOwnTime / 60) + &quot; minutes&quot;);
-                addLine(this.element, &quot;Worst: &quot; + Math.round(result.worstSecondsOwnTime / 60) + &quot; minutes&quot;);
</del><ins>+                addLine(this.element, &quot;Worst: &quot; + Math.round(result.worstSecondsOwnTime / 60) + &quot; minutes (r&quot; + result.revisionWithWorstOwnTime + &quot;)&quot;);
</ins><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (173380 => 173381)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog        2014-09-08 16:11:51 UTC (rev 173380)
+++ trunk/Tools/ChangeLog        2014-09-08 17:05:10 UTC (rev 173381)
</span><span class="lines">@@ -1,3 +1,29 @@
</span><ins>+2014-09-08  Alexey Proskuryakov  &lt;ap@apple.com&gt;
+
+        Dashboard metrics should ignore commits that didn't trigger builds
+        https://bugs.webkit.org/show_bug.cgi?id=136618
+
+        Reviewed by Darin Adler.
+
+        Commits that didn't trigger builds are ones like ChangeLog updates, patches for
+        other platforms etc. It does not make sense to count wait time for these, as it
+        can be arbitrarily long.
+
+        The new algorithm is much slower asymptotically, but it's OK, computers are fast.
+
+        * BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/BuildbotIteration.js:
+        (BuildbotIteration.prototype._parseData): Record changes that triggered the iteration.
+
+        * BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/MetricsAnalyzer.js:
+        We used to walk the timeline to see which revisions are fully tested, but that's not
+        correct. A revision that's only tested by a subset of queues finishes independently
+        of another that's tested by another subset. Now, we just search for the answer for
+        each revision individually.
+
+        * BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/MetricsView.js:
+        (MetricsView.prototype._update.appendQueueResults): Added worst revision number, which
+        the analyzer now reports. Removed best time, which is more confusing than meaningful.
+
</ins><span class="cx"> 2014-09-08  Tibor Meszaros  &lt;tmeszaros.u-szeged@partner.samsung.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Remove EWebLauncher from webkitdirs.pm
</span></span></pre>
</div>
</div>

</body>
</html>