forked from facebook/react
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstats.js
112 lines (104 loc) · 3.37 KB
/
stats.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
'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;