+2015-02-19 Ryosuke Niwa <rniwa@webkit.org>
+
+ Relationship between A/B testing results are unclear
+ https://bugs.webkit.org/show_bug.cgi?id=141810
+
+ Reviewed by Andreas Kling.
+
+ Show a "reference chart" indicating which two points have been tested in each test group pane.
+
+ Now the chart shown at the top of an analysis task page is called the "overview pane", and we use the pane
+ and the domain used in this chart to show charts in each test group.
+
+ Also renamed an array of revisions used in the A/B test results tables from 'revisions' to 'revisionList'.
+
+ * public/v2/analysis.js:
+ (App.TestGroup._fetchTestResults): Renamed from _fetchChartData. Set 'testResults' instead of 'chartData'
+ since this is the results of A/B testing results, not the data for charts shown next to them.
+
+ * public/v2/app.css: Added CSS rules for reference charts.
+
+ * public/v2/app.js:
+ (App.AnalysisTaskController.paneDomain): Set 'overviewPane' and 'overviewDomain' on each test group pane.
+ (App.TestGroupPane._populate): Updated per 'chartData' to 'testResults' rename.
+ (App.TestGroupPane._updateReferenceChart): Get the chart data via the overview pane and find points that
+ identically matches root sets. If one of configuration used a set of revisions for which no measurement
+ was made in the original chart, don't show the reference chart as that would be misleading / confusing.
+ (App.TestGroupPane._computeRepositoryList): Updated per 'chartData' to 'testResults' rename.
+ (App.TestGroupPane._createConfigurationSummary): Ditto. Also renamed 'revisions' to 'revisionList'.
+ In addition, renamed 'buildNumber' to 'buildLabel' and prefixed it with "Build ".
+
+ * public/v2/data.js:
+ (Measurement.prototype.revisionForRepository): Added.
+ (Measurement.prototype.commitTimeForRepository): Cleanup.
+ (TimeSeries.prototype.findPointByRevisions): Added. Finds a point based on a set of revisions.
+
+ * public/v2/index.html: Added the reference chart. Streamlined the status label for each build request
+ by including the build number in the title attribute instead of in the markup.
+
+ * public/v2/interactive-chart.js:
+ (App.InteractiveChartComponent._updateDomain): Fixed a typo introduced as a consequence of r179913.
+ (App.InteractiveChartComponent._computeYAxisDomain): Expand the y-axis to show the highlighted points.
+ (App.InteractiveChartComponent._highlightedItemsChanged): Adjust the y-axis as needed.
+
2015-02-18 Ryosuke Niwa <rniwa@webkit.org>
Analysis task pages are unusable
this.set('highlightedItems', highlightedItems);
this.set('analysisPoints', formatedPoints);
- return [start.time - margin, +end.time + margin];
- }.property('pane.chartData', 'model', 'model'),
+ var paneDomain = [start.time - margin, +end.time + margin];
+
+ var testGroupPanes = this.get('testGroupPanes');
+ if (testGroupPanes) {
+ testGroupPanes.setEach('overviewPane', pane);
+ testGroupPanes.setEach('overviewDomain', paneDomain);
+ }
+
+ return paneDomain;
+ }.property('pane.chartData'),
testSets: function ()
{
var analysisPoints = this.get('analysisPoints');
_populate: function ()
{
var buildRequests = this.get('buildRequests');
- var chartData = this.get('chartData');
- if (!buildRequests || !chartData)
+ var testResults = this.get('testResults');
+ if (!buildRequests || !testResults)
return [];
var repositories = this._computeRepositoryList();
range.min -= margin;
this.set('configurations', configurations);
- }.observes('chartData', 'buildRequests'),
+ }.observes('testResults', 'buildRequests'),
+ _updateReferenceChart: function ()
+ {
+ var configurations = this.get('configurations');
+ var chartData = this.get('overviewPane') ? this.get('overviewPane').get('chartData') : null;
+ if (!configurations || !chartData || this.get('referenceChart'))
+ return;
+
+ var currentTimeSeries = chartData.current;
+ if (!currentTimeSeries)
+ return;
+
+ var repositories = this.get('repositories');
+ var highlightedItems = {};
+ var failedToFindPoint = false;
+ configurations.forEach(function (config) {
+ var revisions = {};
+ config.get('rootSet').get('roots').forEach(function (root) {
+ revisions[root.get('repository').get('id')] = root.get('revision');
+ });
+ var point = currentTimeSeries.findPointByRevisions(revisions);
+ if (!point) {
+ failedToFindPoint = true;
+ return;
+ }
+ highlightedItems[point.measurement.id()] = true;
+ });
+ if (failedToFindPoint)
+ return;
+
+ this.set('referenceChart', {
+ data: chartData,
+ highlightedItems: highlightedItems,
+ });
+ }.observes('configurations', 'overviewPane.chartData'),
_computeRepositoryList: function ()
{
var specifiedRepositories = new Ember.Set();
});
});
var reportedRepositories = new Ember.Set();
- var chartData = this.get('chartData');
+ var testResults = this.get('testResults');
(this.get('buildRequests') || []).forEach(function (request) {
- var point = chartData.current.findPointByBuild(request.get('build'));
+ var point = testResults.current.findPointByBuild(request.get('build'));
if (!point)
return;
_createConfigurationSummary: function (buildRequests, configLetter, range)
{
var repositories = this.get('repositories');
- var chartData = this.get('chartData');
+ var testResults = this.get('testResults');
var requests = buildRequests.map(function (originalRequest) {
- var point = chartData.current.findPointByBuild(originalRequest.get('build'));
+ var point = testResults.current.findPointByBuild(originalRequest.get('build'));
var revisionByRepositoryId = point ? point.measurement.formattedRevisions() : {};
return Ember.ObjectProxy.create({
content: originalRequest,
- revisions: repositories.map(function (repository, index) {
+ revisionList: repositories.map(function (repository, index) {
return (revisionByRepositoryId[repository.get('id')] || {label:null}).label;
}),
value: point ? point.value : null,
valueRange: range,
- formattedValue: point ? chartData.formatWithUnit(point.value) : null,
- buildNumber: point ? point.measurement.buildNumber() : null,
+ formattedValue: point ? testResults.formatWithUnit(point.value) : null,
+ buildLabel: point ? 'Build ' + point.measurement.buildNumber() : null,
});
});
var summaryRevisions = repositories.map(function (repository, index) {
var revision = rootSet ? rootSet.revisionForRepository(repository) : null;
if (!revision)
- return requests[0].get('revisions')[index];
+ return requests[0].get('revisionList')[index];
return Measurement.formatRevisionRange(revision).label;
});
requests.forEach(function (request) {
- var revisions = request.get('revisions');
+ var revisionList = request.get('revisionList');
repositories.forEach(function (repository, index) {
- if (revisions[index] == summaryRevisions[index])
- revisions[index] = null;
+ if (revisionList[index] == summaryRevisions[index])
+ revisionList[index] = null;
});
});
var summary = Ember.Object.create({
isAverage: true,
configLetter: configLetter,
- revisions: summaryRevisions,
- formattedValue: isNaN(mean) ? null : chartData.formatWithDeltaAndUnit(mean, ciDelta),
+ revisionList: summaryRevisions,
+ formattedValue: isNaN(mean) ? null : testResults.formatWithDeltaAndUnit(mean, ciDelta),
value: mean,
confidenceIntervalDelta: ciDelta,
valueRange: range,
statusLabel: App.BuildRequest.aggregateStatuses(requests),
});
- return Ember.Object.create({summary: summary, items: requests});
+ return Ember.Object.create({summary: summary, items: requests, rootSet: rootSet});
},
});