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 d2c98de78aa766e316b436443fef3a54b85ec2cf..0cf4058f4450d883b98e1830d18a019cfac8defc 100644 (file)
@@ -1,3 +1,42 @@
+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.
index d6c409951beeb77d10c5fd1aa660000eb790d1d0..13a571b6fa8a339aaf154e16d82704bc428054b4 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 3760624b768d3126e5ba5225108bd52214144ba0..815c2864a1c8e0b98f1ed862572cd9d128f22db9 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 6653ac43f9af2742e86f037aad38564338d377c9..d06d593cf322bdf0adc5bb88d808ba4cb6d9e6f0 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 4c91967fe1e093696f1836e47740e8d3c8f10d5a..3e2f7a8d175adf89d6cfcd717c203924d7350a5c 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;