perfshield 0.0.1 → 0.0.3
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/README.md +1 -4
- package/examples/simple/perfshield.config.json +1 -4
- package/lib/config.js +3 -21
- package/lib/regression.js +1 -2
- package/lib/report/console.js +1 -1
- package/lib/runner.js +15 -8
- package/lib/stats.js +1 -15
- package/package.json +1 -1
package/README.md
CHANGED
package/lib/config.js
CHANGED
|
@@ -158,26 +158,6 @@ const parseEngineConfig = (value, index, issues) => {
|
|
|
158
158
|
name
|
|
159
159
|
};
|
|
160
160
|
};
|
|
161
|
-
const parseSamplingConditions = (value, issues) => {
|
|
162
|
-
const conditions = asObject(value, "config.sampling.conditions", issues);
|
|
163
|
-
if (!conditions) {
|
|
164
|
-
return null;
|
|
165
|
-
}
|
|
166
|
-
validateKeys(conditions, ["absolute", "relative"], "config.sampling.conditions", issues);
|
|
167
|
-
const absolute = asNumberArray(conditions.absolute, "config.sampling.conditions.absolute", issues, {
|
|
168
|
-
minLength: 1
|
|
169
|
-
});
|
|
170
|
-
const relative = asNumberArray(conditions.relative, "config.sampling.conditions.relative", issues, {
|
|
171
|
-
minLength: 1
|
|
172
|
-
});
|
|
173
|
-
if (!absolute || !relative) {
|
|
174
|
-
return null;
|
|
175
|
-
}
|
|
176
|
-
return {
|
|
177
|
-
absolute,
|
|
178
|
-
relative
|
|
179
|
-
};
|
|
180
|
-
};
|
|
181
161
|
const parseSamplingConfig = (value, issues) => {
|
|
182
162
|
const sampling = asObject(value, "config.sampling", issues);
|
|
183
163
|
if (!sampling) {
|
|
@@ -192,7 +172,9 @@ const parseSamplingConfig = (value, issues) => {
|
|
|
192
172
|
integer: true,
|
|
193
173
|
min: 1
|
|
194
174
|
});
|
|
195
|
-
const conditions =
|
|
175
|
+
const conditions = asNumberArray(sampling.conditions, "config.sampling.conditions", issues, {
|
|
176
|
+
minLength: 1
|
|
177
|
+
});
|
|
196
178
|
if (minSamples == null || timeoutMs == null || !conditions) {
|
|
197
179
|
return null;
|
|
198
180
|
}
|
package/lib/regression.js
CHANGED
|
@@ -3,9 +3,8 @@ export const getRegressions = results => {
|
|
|
3
3
|
const findings = [];
|
|
4
4
|
for (const result of results) {
|
|
5
5
|
for (const entry of result.benchmarks) {
|
|
6
|
-
if (isPositiveInterval(entry.difference.
|
|
6
|
+
if (isPositiveInterval(entry.difference.relative.ci)) {
|
|
7
7
|
findings.push({
|
|
8
|
-
absolute: entry.difference.absolute.ci,
|
|
9
8
|
benchmark: entry.benchmark.name,
|
|
10
9
|
engine: result.engine.name,
|
|
11
10
|
relative: entry.difference.relative.ci
|
package/lib/report/console.js
CHANGED
|
@@ -16,7 +16,7 @@ export const renderConsoleReport = results => {
|
|
|
16
16
|
lines.push(`Engine: ${result.engine.name}`);
|
|
17
17
|
for (const entry of result.benchmarks) {
|
|
18
18
|
const unit = entry.benchmark.unit != null ? ` ${entry.benchmark.unit}` : "";
|
|
19
|
-
const benchmarkLines = [` Benchmark: ${entry.benchmark.name}`, ` baseline mean=${formatNumber(entry.stats.baseline.mean, 4)}${unit} ci=${formatInterval(entry.stats.baseline.meanCI, 4)} sd=${formatNumber(entry.stats.baseline.standardDeviation, 4)}`, ` current mean=${formatNumber(entry.stats.current.mean, 4)}${unit} ci=${formatInterval(entry.stats.current.meanCI, 4)} sd=${formatNumber(entry.stats.current.standardDeviation, 4)}`, ` diff
|
|
19
|
+
const benchmarkLines = [` Benchmark: ${entry.benchmark.name}`, ` baseline mean=${formatNumber(entry.stats.baseline.mean, 4)}${unit} ci=${formatInterval(entry.stats.baseline.meanCI, 4)} sd=${formatNumber(entry.stats.baseline.standardDeviation, 4)}`, ` current mean=${formatNumber(entry.stats.current.mean, 4)}${unit} ci=${formatInterval(entry.stats.current.meanCI, 4)} sd=${formatNumber(entry.stats.current.standardDeviation, 4)}`, ` diff rel mean=${formatRelativeValue(entry.difference.relative.mean, 2)} ci=${formatRelativeInterval(entry.difference.relative.ci, 2)}`];
|
|
20
20
|
lines.push(...benchmarkLines);
|
|
21
21
|
}
|
|
22
22
|
lines.push("");
|
package/lib/runner.js
CHANGED
|
@@ -8,6 +8,12 @@ import { computeDifference, summaryStats } from "./stats.js";
|
|
|
8
8
|
const versions = ["baseline", "current"];
|
|
9
9
|
const autoSampleBatchSize = 10;
|
|
10
10
|
const harnessTempPrefix = "perfshield-harness-";
|
|
11
|
+
const getVersionOrder = seed => {
|
|
12
|
+
if (seed % 2 === 0) {
|
|
13
|
+
return versions;
|
|
14
|
+
}
|
|
15
|
+
return [versions[1], versions[0]];
|
|
16
|
+
};
|
|
11
17
|
const getHarnessPath = () => {
|
|
12
18
|
const override = process.env.WEB_BENCHMARKER_HARNESS_PATH;
|
|
13
19
|
if (override != null) {
|
|
@@ -70,10 +76,13 @@ const collectSamples = async (harness, benchmarks, minSamples) => {
|
|
|
70
76
|
baseline: [],
|
|
71
77
|
current: []
|
|
72
78
|
}));
|
|
79
|
+
let roundRobinSeed = 0;
|
|
73
80
|
for (let iteration = 0; iteration < minSamples; iteration += 1) {
|
|
74
81
|
for (let index = 0; index < benchmarks.length; index += 1) {
|
|
75
82
|
const descriptor = benchmarks[index];
|
|
76
|
-
|
|
83
|
+
const order = getVersionOrder(roundRobinSeed);
|
|
84
|
+
roundRobinSeed += 1;
|
|
85
|
+
for (const version of order) {
|
|
77
86
|
const result = await harness.runSample({
|
|
78
87
|
index,
|
|
79
88
|
iterations: descriptor.iterations,
|
|
@@ -94,12 +103,7 @@ const autoSampleResolved = (samples, conditions) => samples.every(bucket => {
|
|
|
94
103
|
const baselineStats = summaryStats(bucket.baseline);
|
|
95
104
|
const currentStats = summaryStats(bucket.current);
|
|
96
105
|
const diff = computeDifference(baselineStats, currentStats);
|
|
97
|
-
for (const condition of conditions
|
|
98
|
-
if (intervalContains(diff.absolute.ci, condition)) {
|
|
99
|
-
return false;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
for (const condition of conditions.relative) {
|
|
106
|
+
for (const condition of conditions) {
|
|
103
107
|
if (intervalContains(diff.relative.ci, condition)) {
|
|
104
108
|
return false;
|
|
105
109
|
}
|
|
@@ -108,6 +112,7 @@ const autoSampleResolved = (samples, conditions) => samples.every(bucket => {
|
|
|
108
112
|
});
|
|
109
113
|
const autoSample = async (harness, benchmarks, samples, conditions, timeoutMs) => {
|
|
110
114
|
const startTime = Date.now();
|
|
115
|
+
let roundRobinSeed = 0;
|
|
111
116
|
while (Date.now() - startTime < timeoutMs) {
|
|
112
117
|
if (autoSampleResolved(samples, conditions)) {
|
|
113
118
|
return;
|
|
@@ -115,7 +120,9 @@ const autoSample = async (harness, benchmarks, samples, conditions, timeoutMs) =
|
|
|
115
120
|
for (let batch = 0; batch < autoSampleBatchSize; batch += 1) {
|
|
116
121
|
for (let index = 0; index < benchmarks.length; index += 1) {
|
|
117
122
|
const descriptor = benchmarks[index];
|
|
118
|
-
|
|
123
|
+
const order = getVersionOrder(roundRobinSeed);
|
|
124
|
+
roundRobinSeed += 1;
|
|
125
|
+
for (const version of order) {
|
|
119
126
|
const result = await harness.runSample({
|
|
120
127
|
index,
|
|
121
128
|
iterations: descriptor.iterations,
|
package/lib/stats.js
CHANGED
|
@@ -23,10 +23,6 @@ export const samplingDistributionOfTheMean = (distribution, sampleSize) => ({
|
|
|
23
23
|
mean: distribution.mean,
|
|
24
24
|
variance: distribution.variance / sampleSize
|
|
25
25
|
});
|
|
26
|
-
export const samplingDistributionOfAbsoluteDifferenceOfMeans = (a, b) => ({
|
|
27
|
-
mean: b.mean - a.mean,
|
|
28
|
-
variance: a.variance + b.variance
|
|
29
|
-
});
|
|
30
26
|
export const samplingDistributionOfRelativeDifferenceOfMeans = (a, b) => ({
|
|
31
27
|
mean: (b.mean - a.mean) / a.mean,
|
|
32
28
|
variance: (a.variance * b.mean * b.mean + b.variance * a.mean * a.mean) / (a.mean * a.mean * a.mean * a.mean)
|
|
@@ -65,14 +61,9 @@ export const computeDifference = (baseline, current) => {
|
|
|
65
61
|
mean: current.mean,
|
|
66
62
|
variance: current.variance
|
|
67
63
|
}, current.size);
|
|
68
|
-
const absoluteDist = samplingDistributionOfAbsoluteDifferenceOfMeans(baselineDist, currentDist);
|
|
69
64
|
const relativeDist = samplingDistributionOfRelativeDifferenceOfMeans(baselineDist, currentDist);
|
|
70
65
|
const size = Math.min(baseline.size, current.size);
|
|
71
66
|
return {
|
|
72
|
-
absolute: {
|
|
73
|
-
ci: confidenceInterval95(absoluteDist, size),
|
|
74
|
-
mean: absoluteDist.mean
|
|
75
|
-
},
|
|
76
67
|
relative: {
|
|
77
68
|
ci: confidenceInterval95(relativeDist, size),
|
|
78
69
|
mean: relativeDist.mean
|
|
@@ -92,12 +83,7 @@ export const autoSampleConditionsResolved = (resultStats, conditions) => {
|
|
|
92
83
|
if (diff == null) {
|
|
93
84
|
continue;
|
|
94
85
|
}
|
|
95
|
-
for (const condition of conditions
|
|
96
|
-
if (intervalContains(diff.absolute.ci, condition)) {
|
|
97
|
-
return false;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
for (const condition of conditions.relative) {
|
|
86
|
+
for (const condition of conditions) {
|
|
101
87
|
if (intervalContains(diff.relative.ci, condition)) {
|
|
102
88
|
return false;
|
|
103
89
|
}
|