Perf dashboard doesn't show analysis tasks anchored at outliers
authorrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 7 Oct 2015 18:38:07 +0000 (18:38 +0000)
committerrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 7 Oct 2015 18:38:07 +0000 (18:38 +0000)
https://bugs.webkit.org/show_bug.cgi?id=149870

Reviewed by Chris Dumez.

The bug was caused by the computation of start and end times of analysis tasks being dependent on
time series provided to the interactive chart component even though they are already filtered.

Since the interactive chart component shouldn't be messing with the underlying data models, moved
the code to compute start and end times to App.Pane, to where it belongs, and made the moved code use
the unfiltered time series newly exposed on ChartData.

Also fixed a bug in fetch-from-remote.php which resulted in Ember endlessly fetching same JSON files.

* public/admin/fetch-from-remote.php:
(.): Use the full request URI for HTTP requests and caching. Otherwise, we're going to mix up caches
and Ember can start hanging browsers (took me three hours to debug this).

* public/v2/app.js:
(App.Pane._showOutlierChanged): Added. Resets chartData when showOutlier flag has been changed.
(App.Pane.fetchAnalyticRanges): The old code wasn't filtering analysis tasks by platforms and metrics
at all since it relied on the server-side REST API to do the filtering, which I haven't implemented yet.
Filter the results manually instead.
(App.Pane.ranges): Moved the logic to compute startTime and endTime here from InteractiveChartComponent.
(App.PaneController.toggleShowOutlier): Now that App.Pane responds to showOutlier changes, we don't
need to call a private method on it.
(App.AnalysisTaskController._chartDataChanged): When end points are not found, try showing outliers.
This will cause chartData to be modified so just exit early and wait for getting called again.

* public/v2/interactive-chart.js:
(App.InteractiveChartComponent._rangesChanged): The code to compute start and end time has been moved
to App.Pane.ranges.

* public/v2/manifest.js:
(App.Manifest._formatFetchedData): Added unfiltered time series as new properties as they are now used
to compute the end points of analysis tasks when their end points are outliers.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@190676 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Websites/perf.webkit.org/ChangeLog
Websites/perf.webkit.org/public/admin/fetch-from-remote.php
Websites/perf.webkit.org/public/v2/app.js
Websites/perf.webkit.org/public/v2/interactive-chart.js
Websites/perf.webkit.org/public/v2/manifest.js

index d2c98de..0cf4058 100644 (file)
@@ -1,5 +1,44 @@
 2015-10-07  Ryosuke Niwa  <rniwa@webkit.org>
 
+        Perf dashboard doesn't show analysis tasks anchored at outliers
+        https://bugs.webkit.org/show_bug.cgi?id=149870
+
+        Reviewed by Chris Dumez.
+
+        The bug was caused by the computation of start and end times of analysis tasks being dependent on
+        time series provided to the interactive chart component even though they are already filtered.
+
+        Since the interactive chart component shouldn't be messing with the underlying data models, moved
+        the code to compute start and end times to App.Pane, to where it belongs, and made the moved code use
+        the unfiltered time series newly exposed on ChartData.
+
+        Also fixed a bug in fetch-from-remote.php which resulted in Ember endlessly fetching same JSON files.
+
+        * public/admin/fetch-from-remote.php:
+        (.): Use the full request URI for HTTP requests and caching. Otherwise, we're going to mix up caches
+        and Ember can start hanging browsers (took me three hours to debug this).
+
+        * public/v2/app.js:
+        (App.Pane._showOutlierChanged): Added. Resets chartData when showOutlier flag has been changed.
+        (App.Pane.fetchAnalyticRanges): The old code wasn't filtering analysis tasks by platforms and metrics
+        at all since it relied on the server-side REST API to do the filtering, which I haven't implemented yet.
+        Filter the results manually instead.
+        (App.Pane.ranges): Moved the logic to compute startTime and endTime here from InteractiveChartComponent.
+        (App.PaneController.toggleShowOutlier): Now that App.Pane responds to showOutlier changes, we don't
+        need to call a private method on it.
+        (App.AnalysisTaskController._chartDataChanged): When end points are not found, try showing outliers.
+        This will cause chartData to be modified so just exit early and wait for getting called again.
+
+        * public/v2/interactive-chart.js:
+        (App.InteractiveChartComponent._rangesChanged): The code to compute start and end time has been moved
+        to App.Pane.ranges.
+
+        * public/v2/manifest.js:
+        (App.Manifest._formatFetchedData): Added unfiltered time series as new properties as they are now used
+        to compute the end points of analysis tasks when their end points are outliers.
+
+2015-10-07  Ryosuke Niwa  <rniwa@webkit.org>
+
         Unreviewed. Fix a typo in r190645.
 
         * public/include/db.php:
index d6c4099..13a571b 100644 (file)
@@ -38,6 +38,6 @@ function fetch_remote($remote_server, $remote_url)
     return @file_get_contents($remote_url, false, $context);
 }
 
-main(array_get($_SERVER, 'PATH_INFO', ''));
+main(array_get($_SERVER, 'REQUEST_URI', ''));
 
 ?>
index 3760624..815c286 100644 (file)
@@ -378,6 +378,12 @@ App.Pane = Ember.Object.extend({
         this.set('metric', result.metric);
         this._setNewChartData(result.data);
     },
+    _showOutlierChanged: function ()
+    {
+        var chartData = this.get('chartData');
+        if (chartData)
+            this._setNewChartData(chartData);
+    }.observes('showOutlier'),
     _setNewChartData: function (chartData)
     {
         var newChartData = {};
@@ -420,15 +426,43 @@ App.Pane = Ember.Object.extend({
         var metricId = this.get('metricId');
         var self = this;
         this.get('store')
-            .find('analysisTask', {platform: platformId, metric: metricId})
+            .findAll('analysisTask') // FIXME: Fetch only analysis tasks relevant for this pane.
             .then(function (tasks) {
-                self.set('analyticRanges', tasks.filter(function (task) { return task.get('startRun') && task.get('endRun'); }));
+                self.set('analyticRanges', tasks.filter(function (task) {
+                    return task.get('platform').get('id') == platformId
+                        && task.get('metric').get('id') == metricId
+                        && task.get('startRun') && task.get('endRun');
+                }));
             });
     },
     ranges: function ()
     {
-        return this.getWithDefault('analyticRanges', []).concat(this.getWithDefault('testRangeCandidates', []));
-    }.property('analyticRanges', 'testRangeCandidates'),
+        var chartData = this.get('chartData');
+        if (!chartData || !chartData.unfilteredCurrentTimeSeries)
+            return [];
+
+        function midPoint(firstPoint, secondPoint) {
+            if (firstPoint && secondPoint)
+                return (+firstPoint.time + +secondPoint.time) / 2;
+            if (firstPoint)
+                return firstPoint.time;
+            return secondPoint.time;
+        }
+
+        var timeSeries = chartData.unfilteredCurrentTimeSeries;
+        var ranges = this.getWithDefault('analyticRanges', []);
+        var testranges = this.getWithDefault('testRangeCandidates', []);
+        return this.getWithDefault('analyticRanges', []).concat(this.getWithDefault('testRangeCandidates', [])).map(function (range) {
+            var start = timeSeries.findPointByMeasurementId(range.get('startRun'));
+            var end = timeSeries.findPointByMeasurementId(range.get('endRun'));
+
+            return Ember.ObjectProxy.create({
+                content: range,
+                startTime: start ? midPoint(timeSeries.previousPoint(start), start) : null,
+                endTime: end ? midPoint(end, timeSeries.nextPoint(end)) : null,
+            });
+        });
+    }.property('chartData', 'analyticRanges', 'testRangeCandidates'),
     _isValidId: function (id)
     {
         if (typeof(id) == "number")
@@ -1013,12 +1047,7 @@ App.PaneController = Ember.ObjectController.extend({
         },
         toggleShowOutlier: function ()
         {
-            var pane = this.get('model');
-            pane.toggleProperty('showOutlier');
-            var chartData = pane.get('chartData');
-            if (!chartData)
-                return;
-            pane._setNewChartData(chartData);
+            this.get('model').toggleProperty('showOutlier');
         },
         createAnalysisTask: function ()
         {
@@ -1285,13 +1314,15 @@ App.AnalysisTaskController = Ember.Controller.extend({
             return null;
 
         var currentTimeSeries = chartData.current;
-        if (!currentTimeSeries)
-            return null; // FIXME: Report an error.
+        Ember.assert('chartData.current should always be defined', currentTimeSeries);
 
         var start = currentTimeSeries.findPointByMeasurementId(this.get('model').get('startRun'));
         var end = currentTimeSeries.findPointByMeasurementId(this.get('model').get('endRun'));
-        if (!start || !end)
-            return null; // FIXME: Report an error.
+        if (!start || !end) {
+            if (!pane.get('showOutlier'))
+                pane.set('showOutlier', true);
+            return;
+        }
 
         var highlightedItems = {};
         highlightedItems[start.measurement.id()] = true;
index 6653ac4..d06d593 100644 (file)
@@ -618,24 +618,11 @@ App.InteractiveChartComponent = Ember.Component.extend({
     }.observes('highlightedItems'),
     _rangesChanged: function ()
     {
-        if (!this._currentTimeSeries)
-            return;
-
-        function midPoint(firstPoint, secondPoint) {
-            if (firstPoint && secondPoint)
-                return (+firstPoint.time + +secondPoint.time) / 2;
-            if (firstPoint)
-                return firstPoint.time;
-            return secondPoint.time;
-        }
-        var currentTimeSeries = this._currentTimeSeries;
         var linkRoute = this.get('rangeRoute');
         this.set('rangeBars', (this.get('ranges') || []).map(function (range) {
-            var start = currentTimeSeries.findPointByMeasurementId(range.get('startRun'));
-            var end = currentTimeSeries.findPointByMeasurementId(range.get('endRun'));
             return Ember.Object.create({
-                startTime: midPoint(currentTimeSeries.previousPoint(start), start),
-                endTime: midPoint(end, currentTimeSeries.nextPoint(end)),
+                startTime: range.get('startTime'),
+                endTime: range.get('endTime'),
                 range: range,
                 left: null,
                 right: null,
index 4c91967..3e2f7a8 100644 (file)
@@ -361,12 +361,20 @@ App.Manifest = Ember.Controller.extend({
         var currentTimeSeries = configurations.current.timeSeriesByCommitTime(false);
         var baselineTimeSeries = configurations.baseline ? configurations.baseline.timeSeriesByCommitTime(false) : null;
         var targetTimeSeries = configurations.target ? configurations.target.timeSeriesByCommitTime(false) : null;
-        var unfilteredCurrentTimeSeries, unfilteredBaselineTimeSeries, unfilteredTargetTimeSeries;
+
+        var unfilteredCurrentTimeSeries = configurations.current.timeSeriesByCommitTime(true);
+        var unfilteredBaselineTimeSeries = configurations.baseline ? configurations.baseline.timeSeriesByCommitTime(true) : null;
+        var unfilteredTargetTimeSeries = configurations.target ? configurations.target.timeSeriesByCommitTime(true) : null;
 
         return {
             current: currentTimeSeries,
             baseline: baselineTimeSeries,
             target: targetTimeSeries,
+
+            unfilteredCurrentTimeSeries: unfilteredCurrentTimeSeries,
+            unfilteredBaselineTimeSeries: unfilteredBaselineTimeSeries,
+            unfilteredTargetTimeSeries: unfilteredTargetTimeSeries,
+
             formatWithDeltaAndUnit: function (value, delta)
             {
                 return this.formatter(value) + (delta && !isNaN(delta) ? ' \u00b1 ' + deltaFormatterWithoutSign(delta) : '');
@@ -376,11 +384,6 @@ App.Manifest = Ember.Controller.extend({
             smallerIsBetter: smallerIsBetter,
             showOutlier: function (show)
             {
-                if (!unfilteredCurrentTimeSeries) {
-                    unfilteredCurrentTimeSeries = configurations.current.timeSeriesByCommitTime(true);
-                    unfilteredBaselineTimeSeries = configurations.baseline ? configurations.baseline.timeSeriesByCommitTime(true) : null;
-                    unfilteredTargetTimeSeries = configurations.target ? configurations.target.timeSeriesByCommitTime(true) : null;
-                }
                 this.current = show ? unfilteredCurrentTimeSeries : currentTimeSeries;
                 this.baseline = show ? unfilteredBaselineTimeSeries : baselineTimeSeries;
                 this.target = show ? unfilteredTargetTimeSeries : targetTimeSeries;