ui/perfherder/compare/CompareView.jsx (245 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, phTimeRanges } from '../perf-helpers/constants'; import withValidation from '../Validation'; import CompareTableView from './CompareTableView'; class CompareView extends React.PureComponent { getInterval = (oldTimestamp, newTimestamp) => { const now = new Date().getTime() / 1000; let timeRange = Math.min(oldTimestamp, newTimestamp); timeRange = Math.round(now - timeRange); const newTimeRange = phTimeRanges.find((time) => timeRange <= time.value); return newTimeRange.value; }; queryParams = (repository, interval, framework) => ({ repository, framework, interval, no_subtests: true, replicates: false, }); getQueryParams = (timeRange, framework) => { const { originalProject, newProject, originalRevision, newRevision, newResultSet, originalResultSet, replicates, } = this.props.validated; let originalParams; let interval; if (originalRevision) { interval = this.getInterval( originalResultSet.push_timestamp, newResultSet.push_timestamp, ); originalParams = this.queryParams( originalProject, interval, framework.id, ); originalParams.revision = originalRevision; } else { interval = timeRange.value; const startDateMs = (newResultSet.push_timestamp - interval) * 1000; const endDateMs = newResultSet.push_timestamp * 1000; originalParams = this.queryParams( originalProject, interval, framework.id, ); originalParams.startday = new Date(startDateMs) .toISOString() .slice(0, -5); originalParams.endday = new Date(endDateMs).toISOString().slice(0, -5); } const newParams = this.queryParams(newProject, interval, framework.id); newParams.revision = newRevision; if (replicates) { originalParams.replicates = true; newParams.replicates = true; } return [originalParams, newParams]; }; createLinks = (oldResults, newResults, timeRange, framework, app) => { const { originalProject, newProject, originalRevision, newRevision, } = this.props.validated; let links = []; const hasSubtests = (oldResults && oldResults.has_subtests) || (newResults && newResults.has_subtests); if (hasSubtests) { const params = { originalProject, newProject, newRevision, originalSignature: oldResults ? oldResults.signature_id : null, newSignature: newResults ? newResults.signature_id : null, framework: framework.id, application: app, }; if (originalRevision) { params.originalRevision = originalRevision; } else { params.selectedTimeRange = timeRange.value; } const detailsLink = `./comparesubtest${createQueryParams(params)}`; links.push({ title: 'subtests', to: detailsLink, }); } 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 { rowNames, tableNames, framework, timeRange } = state; let compareResults = new Map(); const oldStddevVariance = {}; const newStddevVariance = {}; const testsWithNoise = []; tableNames.forEach((testName) => { rowNames.forEach((value) => { if (!oldStddevVariance[value]) { oldStddevVariance[value] = { values: [], lower_is_better: true, frameworkID: framework.id, }; } if (!newStddevVariance[value]) { newStddevVariance[value] = { values: [], frameworkID: framework.id, }; } const key = `${testName} ${value}`; const oldResults = origResultsMap.get(key); const newResults = newResultsMap.get(key); const cmap = getCounterMap(testName, oldResults, newResults); if (cmap.isEmpty) { return; } 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; } cmap.name = value; if ( cmap.originalStddevPct !== undefined && cmap.newStddevPct !== undefined ) { if (cmap.originalStddevPct < 50.0 && cmap.newStddevPct < 50.0) { oldStddevVariance[value].values.push( Math.round(cmap.originalStddevPct * 100) / 100, ); newStddevVariance[value].values.push( Math.round(cmap.newStddevPct * 100) / 100, ); } else { const noise = { baseStddev: cmap.originalStddevPct, newStddev: cmap.newStddevPct, platform: value, testname: testName, }; testsWithNoise.push(noise); } } cmap.links = this.createLinks( oldResults, newResults, timeRange, framework, cmap.app, ); if (compareResults.has(testName)) { compareResults.get(testName).push(cmap); } else { compareResults.set(testName, [cmap]); } }); }); rowNames.forEach((value) => { const cmap = getCounterMap( noiseMetricTitle, oldStddevVariance[value], newStddevVariance[value], ); if (cmap.isEmpty) { return; } compareResults = createNoiseMetric(cmap, value, compareResults); }); compareResults = new Map([...compareResults.entries()].sort()); const updates = { compareResults, testsWithNoise, loading: false }; this.props.updateAppState({ compareData: compareResults }); const resultsArr = Array.from(compareResults.keys()); const testsNoResults = difference(tableNames, resultsArr).sort().join(', '); if (testsNoResults.length) { updates.testsNoResults = testsNoResults; } return updates; }; getHashFragment = () => this.props.location.hash; render() { return ( <CompareTableView {...this.props} getQueryParams={this.getQueryParams} getDisplayResults={this.getDisplayResults} filterByFramework /> ); } } CompareView.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, framework: PropTypes.string, updateParams: PropTypes.func.isRequired, }), }; CompareView.defaultProps = { validated: PropTypes.shape({}), }; const requiredParams = new Set([ 'originalProject', 'newProject', 'newRevision', ]); export default withValidation({ requiredParams })(CompareView);