perfshield 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/stats.js ADDED
@@ -0,0 +1,108 @@
1
+ import jstat from "jstat";
2
+ const sumOf = values => values.reduce((total, value) => total + value, 0);
3
+ const squareResiduals = (values, mean) => values.map(value => {
4
+ const diff = value - mean;
5
+ return diff * diff;
6
+ });
7
+ export const confidenceInterval95 = (distribution, size) => {
8
+ if (size <= 1) {
9
+ return {
10
+ high: distribution.mean,
11
+ low: distribution.mean
12
+ };
13
+ }
14
+ const t = jstat.studentt.inv(1 - 0.05 / 2, size - 1);
15
+ const stdDev = Math.sqrt(distribution.variance);
16
+ const margin = t * stdDev;
17
+ return {
18
+ high: distribution.mean + margin,
19
+ low: distribution.mean - margin
20
+ };
21
+ };
22
+ export const samplingDistributionOfTheMean = (distribution, sampleSize) => ({
23
+ mean: distribution.mean,
24
+ variance: distribution.variance / sampleSize
25
+ });
26
+ export const samplingDistributionOfAbsoluteDifferenceOfMeans = (a, b) => ({
27
+ mean: b.mean - a.mean,
28
+ variance: a.variance + b.variance
29
+ });
30
+ export const samplingDistributionOfRelativeDifferenceOfMeans = (a, b) => ({
31
+ mean: (b.mean - a.mean) / a.mean,
32
+ variance: (a.variance * b.mean * b.mean + b.variance * a.mean * a.mean) / (a.mean * a.mean * a.mean * a.mean)
33
+ });
34
+ export const summaryStats = values => {
35
+ if (values.length === 0) {
36
+ throw new Error("Cannot compute stats for an empty sample set.");
37
+ }
38
+ const size = values.length;
39
+ const mean = sumOf(values) / size;
40
+ const residuals = squareResiduals(values, mean);
41
+ const variance = size > 1 ? sumOf(residuals) / (size - 1) : 0;
42
+ const standardDeviation = Math.sqrt(variance);
43
+ const relativeStandardDeviation = mean === 0 ? 0 : standardDeviation / mean;
44
+ return {
45
+ mean,
46
+ meanCI: confidenceInterval95(samplingDistributionOfTheMean({
47
+ mean,
48
+ variance
49
+ }, size), size),
50
+ relativeStandardDeviation,
51
+ size,
52
+ standardDeviation,
53
+ variance
54
+ };
55
+ };
56
+ export const computeDifference = (baseline, current) => {
57
+ if (baseline.mean === 0) {
58
+ throw new Error("Cannot compute relative difference with baseline mean 0.");
59
+ }
60
+ const baselineDist = samplingDistributionOfTheMean({
61
+ mean: baseline.mean,
62
+ variance: baseline.variance
63
+ }, baseline.size);
64
+ const currentDist = samplingDistributionOfTheMean({
65
+ mean: current.mean,
66
+ variance: current.variance
67
+ }, current.size);
68
+ const absoluteDist = samplingDistributionOfAbsoluteDifferenceOfMeans(baselineDist, currentDist);
69
+ const relativeDist = samplingDistributionOfRelativeDifferenceOfMeans(baselineDist, currentDist);
70
+ const size = Math.min(baseline.size, current.size);
71
+ return {
72
+ absolute: {
73
+ ci: confidenceInterval95(absoluteDist, size),
74
+ mean: absoluteDist.mean
75
+ },
76
+ relative: {
77
+ ci: confidenceInterval95(relativeDist, size),
78
+ mean: relativeDist.mean
79
+ }
80
+ };
81
+ };
82
+ export const computeDifferences = stats => stats.map(result => ({
83
+ ...result,
84
+ differences: stats.map(other => other === result ? null : computeDifference(other.stats, result.stats))
85
+ }));
86
+ const intervalContains = (interval, value) => interval.low <= value && value <= interval.high;
87
+ export const autoSampleConditionsResolved = (resultStats, conditions) => {
88
+ for (const {
89
+ differences
90
+ } of resultStats) {
91
+ for (const diff of differences) {
92
+ if (diff == null) {
93
+ continue;
94
+ }
95
+ for (const condition of conditions.absolute) {
96
+ if (intervalContains(diff.absolute.ci, condition)) {
97
+ return false;
98
+ }
99
+ }
100
+ for (const condition of conditions.relative) {
101
+ if (intervalContains(diff.relative.ci, condition)) {
102
+ return false;
103
+ }
104
+ }
105
+ }
106
+ }
107
+ return true;
108
+ };
package/lib/types.js ADDED
File without changes
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "perfshield",
3
+ "version": "0.0.1",
4
+ "description": "A tool for doing web benchmarking across multiple JS engines and with statistical signifigance",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "bin": {
8
+ "perfshield": "lib/cli.js"
9
+ },
10
+ "files": [
11
+ "lib/**",
12
+ "README.md",
13
+ "examples/**"
14
+ ],
15
+ "dependencies": {
16
+ "jstat": "1.9.6"
17
+ },
18
+ "devDependencies": {
19
+ "@babel/cli": "^7.28.3",
20
+ "@babel/core": "^7.28.5",
21
+ "@babel/preset-flow": "^7.27.1",
22
+ "@ianvs/prettier-plugin-sort-imports": "^4.7.0",
23
+ "@nkzw/eslint-config": "^3.2.1",
24
+ "@prettier/plugin-hermes": "^0.1.3",
25
+ "babel-plugin-syntax-hermes-parser": "^0.33.0",
26
+ "babel-jest": "^30.0.5",
27
+ "eslint": "^9.33.0",
28
+ "flow-typed": "^4.1.1",
29
+ "flow-bin": "^0.295.0",
30
+ "hermes-eslint": "^0.33.0",
31
+ "jest": "^30.0.5"
32
+ },
33
+ "scripts": {
34
+ "bench:compare": "node src/cli.js compare",
35
+ "bench:prepare": "node src/cli.js prepare",
36
+ "build": "rm -rf lib && babel src --out-dir lib --extensions .js,.jsx",
37
+ "flow-typed": "flow-typed install",
38
+ "format": "prettier . --write",
39
+ "flow": "flow check",
40
+ "lint": "eslint . --ext .js,.jsx --no-error-on-unmatched-pattern",
41
+ "test": "NODE_OPTIONS=--experimental-vm-modules jest --passWithNoTests"
42
+ }
43
+ }