ui/perfherder/compare/CompareSubtestsView.jsx (229 lines of code) (raw):
import React from 'react';
import PropTypes from 'prop-types';
import difference from 'lodash/difference';
import { createQueryParams } from '../../helpers/url';
import {
createNoiseMetric,
getCounterMap,
createGraphsLinks,
} from '../perf-helpers/helpers';
import { noiseMetricTitle } from '../perf-helpers/constants';
import withValidation from '../Validation';
import CompareTableView from './CompareTableView';
class CompareSubtestsView extends React.PureComponent {
createQueryParams = (parentSignature, repository, framework) => ({
parent_signature: parentSignature,
framework,
repository,
replicates: false,
});
getQueryParams = (timeRange, framework) => {
const {
originalProject,
newProject,
originalRevision,
newRevision,
newResultSet,
originalSignature,
newSignature,
replicates,
} = this.props.validated;
const originalParams = this.createQueryParams(
originalSignature,
originalProject,
framework.id,
);
if (originalRevision) {
originalParams.revision = originalRevision;
} else {
const startDateMs =
(newResultSet.push_timestamp - timeRange.value) * 1000;
const endDateMs = newResultSet.push_timestamp * 1000;
originalParams.startday = new Date(startDateMs)
.toISOString()
.slice(0, -5);
originalParams.endday = new Date(endDateMs).toISOString().slice(0, -5);
}
const newParams = this.createQueryParams(
newSignature,
newProject,
framework.id,
);
newParams.revision = newRevision;
if (replicates) {
originalParams.replicates = true;
newParams.replicates = true;
}
return [originalParams, newParams];
};
createLinks = (oldResults, newResults, timeRange, framework) => {
const {
originalProject,
newProject,
originalRevision,
newRevision,
} = this.props.validated;
let links = [];
if (
(framework.name === 'talos' ||
framework.name === 'raptor' ||
framework.name === 'devtools') &&
originalRevision
) {
const params = {
originalProject,
newProject,
originalRevision,
newRevision,
originalSubtestSignature: oldResults ? oldResults.signature_id : null,
newSubtestSignature: newResults ? newResults.signature_id : null,
};
links.push({
title: 'replicates',
to: `./comparesubtestdistribution${createQueryParams(params)}`,
});
}
const signatureHash = !oldResults
? newResults.signature_id
: oldResults.signature_id;
links = createGraphsLinks(
this.props.validated,
links,
framework,
timeRange,
signatureHash,
);
return links;
};
getDisplayResults = (origResultsMap, newResultsMap, state) => {
const { originalSignature, newSignature } = this.props.validated;
const { tableNames, rowNames, framework, timeRange } = state;
const testsWithNoise = [];
let compareResults = new Map();
const parentTestName = tableNames[0];
const oldStddevVariance = {
values: [],
lower_is_better: true,
frameworkID: framework.id,
};
const newStddevVariance = {
values: [],
lower_is_better: true,
frameworkID: framework.id,
};
rowNames.forEach((testName) => {
const oldResults = origResultsMap.get(testName);
const newResults = newResultsMap.get(testName);
const cmap = getCounterMap(testName, oldResults, newResults);
if (cmap.isEmpty) {
return;
}
cmap.name = testName;
if (oldResults !== undefined) {
cmap.suite = oldResults.suite;
cmap.baseColumnMeasurementUnit = oldResults.measurement_unit;
cmap.app = oldResults.application;
}
if (newResults !== undefined) {
cmap.suite = newResults.suite;
cmap.newColumnMeasurementUnit = newResults.measurement_unit;
cmap.app = newResults.application;
}
if (
(oldResults && oldResults.parent_signature === originalSignature) ||
(oldResults && oldResults.parent_signature === newSignature) ||
newResults.parent_signature === originalSignature ||
newResults.parent_signature === newSignature
) {
cmap.highlightedTest = true;
}
if (
cmap.originalStddevPct !== undefined &&
cmap.newStddevPct !== undefined
) {
if (cmap.originalStddevPct < 50.0 && cmap.newStddevPct < 50.0) {
oldStddevVariance.values.push(
Math.round(cmap.originalStddevPct * 100) / 100,
);
newStddevVariance.values.push(
Math.round(cmap.newStddevPct * 100) / 100,
);
} else {
const noise = {
baseStddev: cmap.originalStddevPct,
newStddev: cmap.newStddevPct,
testname: testName,
};
testsWithNoise.push(noise);
}
}
cmap.links = this.createLinks(
oldResults,
newResults,
timeRange,
framework,
);
if (compareResults.has(parentTestName)) {
compareResults.get(parentTestName).push(cmap);
} else {
compareResults.set(parentTestName, [cmap]);
}
});
const cmap = getCounterMap(
noiseMetricTitle,
oldStddevVariance,
newStddevVariance,
);
if (!cmap.isEmpty) {
compareResults = createNoiseMetric(cmap, parentTestName, compareResults);
}
compareResults = new Map([...compareResults.entries()].sort());
const updates = { compareResults, testsWithNoise, loading: false };
if (compareResults.size === 0) {
return updates;
}
const resultsArr = compareResults
.get(parentTestName)
.map((value) => value.name);
const testsNoResults = difference(rowNames, resultsArr).sort().join(', ');
if (testsNoResults.length) {
updates.testsNoResults = testsNoResults;
}
return updates;
};
render() {
return (
<CompareTableView
{...this.props}
getQueryParams={this.getQueryParams}
getDisplayResults={this.getDisplayResults}
hasSubtests
/>
);
}
}
CompareSubtestsView.propTypes = {
projects: PropTypes.arrayOf(PropTypes.shape({})).isRequired,
validated: PropTypes.shape({
originalResultSet: PropTypes.shape({}),
newResultSet: PropTypes.shape({}),
newRevision: PropTypes.string,
originalProject: PropTypes.string,
newProject: PropTypes.string,
originalRevision: PropTypes.string,
updateParams: PropTypes.func.isRequired,
newSignature: PropTypes.string,
originalSignature: PropTypes.string,
}),
};
CompareSubtestsView.defaultProps = {
validated: PropTypes.shape({}),
};
const requiredParams = new Set([
'originalProject',
'newProject',
'newRevision',
'originalSignature',
'newSignature',
]);
export default withValidation({ requiredParams })(CompareSubtestsView);