113 lines
3.4 KiB
JavaScript
113 lines
3.4 KiB
JavaScript
'use strict';
|
|
|
|
const chalk = require('chalk');
|
|
const Table = require('cli-table');
|
|
|
|
function percentChange(prev, current, prevSem, currentSem) {
|
|
const [mean, sd] = calculateMeanAndSdOfRatioFromDeltaMethod(
|
|
prev,
|
|
current,
|
|
prevSem,
|
|
currentSem
|
|
);
|
|
const pctChange = +(mean * 100).toFixed(1);
|
|
const ci95 = +(100 * 1.96 * sd).toFixed(1);
|
|
|
|
const ciInfo = ci95 > 0 ? ` +- ${ci95} %` : '';
|
|
const text = `${pctChange > 0 ? '+' : ''}${pctChange} %${ciInfo}`;
|
|
if (pctChange + ci95 < 0) {
|
|
return chalk.green(text);
|
|
} else if (pctChange - ci95 > 0) {
|
|
return chalk.red(text);
|
|
} else {
|
|
// Statistically insignificant.
|
|
return text;
|
|
}
|
|
}
|
|
|
|
function calculateMeanAndSdOfRatioFromDeltaMethod(
|
|
meanControl,
|
|
meanTest,
|
|
semControl,
|
|
semTest
|
|
) {
|
|
const mean =
|
|
(meanTest - meanControl) / meanControl -
|
|
(Math.pow(semControl, 2) * meanTest) / Math.pow(meanControl, 3);
|
|
const variance =
|
|
Math.pow(semTest / meanControl, 2) +
|
|
Math.pow(semControl * meanTest, 2) / Math.pow(meanControl, 4);
|
|
return [mean, Math.sqrt(variance)];
|
|
}
|
|
|
|
function addBenchmarkResults(table, localResults, remoteMasterResults) {
|
|
const benchmarks = Object.keys(
|
|
(localResults && localResults.benchmarks) ||
|
|
(remoteMasterResults && remoteMasterResults.benchmarks)
|
|
);
|
|
benchmarks.forEach(benchmark => {
|
|
const rowHeader = [chalk.white.bold(benchmark)];
|
|
if (remoteMasterResults) {
|
|
rowHeader.push(chalk.white.bold('Time'));
|
|
}
|
|
if (localResults) {
|
|
rowHeader.push(chalk.white.bold('Time'));
|
|
}
|
|
if (localResults && remoteMasterResults) {
|
|
rowHeader.push(chalk.white.bold('Diff'));
|
|
}
|
|
table.push(rowHeader);
|
|
|
|
const measurements =
|
|
(localResults && localResults.benchmarks[benchmark].averages) ||
|
|
(remoteMasterResults &&
|
|
remoteMasterResults.benchmarks[benchmark].averages);
|
|
measurements.forEach((measurement, i) => {
|
|
const row = [chalk.gray(measurement.entry)];
|
|
let remoteMean;
|
|
let remoteSem;
|
|
if (remoteMasterResults) {
|
|
remoteMean = remoteMasterResults.benchmarks[benchmark].averages[i].mean;
|
|
remoteSem = remoteMasterResults.benchmarks[benchmark].averages[i].sem;
|
|
// https://en.wikipedia.org/wiki/1.96 gives a 99% confidence interval.
|
|
const ci95 = remoteSem * 1.96;
|
|
row.push(
|
|
chalk.white(+remoteMean.toFixed(2) + ' ms +- ' + ci95.toFixed(2))
|
|
);
|
|
}
|
|
let localMean;
|
|
let localSem;
|
|
if (localResults) {
|
|
localMean = localResults.benchmarks[benchmark].averages[i].mean;
|
|
localSem = localResults.benchmarks[benchmark].averages[i].sem;
|
|
const ci95 = localSem * 1.96;
|
|
row.push(
|
|
chalk.white(+localMean.toFixed(2) + ' ms +- ' + ci95.toFixed(2))
|
|
);
|
|
}
|
|
if (localResults && remoteMasterResults) {
|
|
row.push(percentChange(remoteMean, localMean, remoteSem, localSem));
|
|
}
|
|
table.push(row);
|
|
});
|
|
});
|
|
}
|
|
|
|
function printResults(localResults, remoteMasterResults) {
|
|
const head = [''];
|
|
if (remoteMasterResults) {
|
|
head.push(chalk.yellow.bold('Remote (Merge Base)'));
|
|
}
|
|
if (localResults) {
|
|
head.push(chalk.green.bold('Local (Current Branch)'));
|
|
}
|
|
if (localResults && remoteMasterResults) {
|
|
head.push('');
|
|
}
|
|
const table = new Table({head});
|
|
addBenchmarkResults(table, localResults, remoteMasterResults);
|
|
console.log(table.toString());
|
|
}
|
|
|
|
module.exports = printResults;
|