Skip to content

Commit cb8ecf8

Browse files
committed
feat: Isolate benchmark runs to new browser instances
Ensures each benchmark iteration starts with a completely clean browser state. Launches and closes a new browser instance for every individual benchmark measurement. Refactors the benchmark execution logic into a dedicated function for single page operations. Improves the reliability and accuracy of performance measurements by preventing potential state leakage or side effects between runs.
1 parent 92c90de commit cb8ecf8

File tree

1 file changed

+31
-24
lines changed

1 file changed

+31
-24
lines changed

src/main.js

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -80,29 +80,43 @@ function ensureBenchmarkHtmlTemplates(benchmarkRoot) {
8080
core.endGroup();
8181
}
8282

83-
async function runSingleBenchmark(browser, url, label) {
83+
async function runIsolatedBenchmark(url, label, browserArgs) {
8484
const sampleFPS = [];
8585

8686
for (let i = 0; i < REPEATS; i++) {
87-
const page = await browser.newPage();
88-
await page.setViewportSize({ width: 800, height: 600 });
89-
await page.goto(url, { waitUntil: 'load', timeout: 60_000 });
90-
91-
core.info(`Measurement ${i + 1}/${REPEATS} for ${label}`);
92-
await page.waitForFunction(() => window.benchmarkResult, {
93-
timeout: 60_000
94-
});
95-
const result = await page.evaluate(() => window.benchmarkResult);
96-
sampleFPS.push(result.fps);
97-
await page.close();
87+
const browser = await chromium.launch({ headless: true, args: browserArgs });
88+
try {
89+
await runSingleBenchmark(browser, url, label, sampleFPS, i);
90+
} finally {
91+
try {
92+
for (const context of browser.contexts()) {
93+
await context.close().catch(() => {});
94+
}
95+
await browser.close();
96+
} catch {
97+
throw new Error('Failed to close browser');
98+
}
99+
}
98100
}
99-
100101
const avg = sampleFPS.reduce((a, b) => a + b, 0) / sampleFPS.length;
101102
const stddev = Math.sqrt(sampleFPS.reduce((s, n) => s + (n - avg) ** 2, 0) / sampleFPS.length);
102-
103103
return { avg, stddev, samples: sampleFPS };
104104
}
105105

106+
async function runSingleBenchmark(browser, url, label, sampleFPS, i) {
107+
const page = await browser.newPage();
108+
await page.setViewportSize({ width: 800, height: 600 });
109+
await page.goto(url, { waitUntil: 'load', timeout: 60_000 });
110+
111+
core.info(`Measurement ${i + 1}/${REPEATS} for ${label}`);
112+
await page.waitForFunction(() => window.benchmarkResult, {
113+
timeout: 60_000
114+
});
115+
const result = await page.evaluate(() => window.benchmarkResult);
116+
sampleFPS.push(result.fps);
117+
await page.close();
118+
}
119+
106120
export async function run() {
107121
let server;
108122
let browser;
@@ -129,14 +143,7 @@ export async function run() {
129143
const indexFiles = findIndexModules(benchmarkFullPath);
130144
if (indexFiles.length === 0) throw new Error('No index.mjs benchmark entrypoints found.');
131145

132-
const browserArgs = [
133-
'--use-gl=angle',
134-
'--disable-web-security'
135-
];
136-
137-
core.startGroup('Launch browser');
138-
browser = await chromium.launch({ headless: true, args: browserArgs });
139-
core.endGroup();
146+
const browserArgs = ['--use-gl=angle', '--disable-web-security'];
140147

141148
const comparisons = [];
142149
core.startGroup('Run dev vs local benchmarks');
@@ -151,8 +158,8 @@ export async function run() {
151158

152159
core.info(`Benchmark: ${name}`);
153160

154-
const devResult = await runSingleBenchmark(browser, devURL, `${name} [dev]`);
155-
const localResult = await runSingleBenchmark(browser, localURL, `${name} [local]`);
161+
const devResult = await runIsolatedBenchmark(devURL, `${name} [dev]`, browserArgs);
162+
const localResult = await runIsolatedBenchmark(localURL, `${name} [local]`, browserArgs);
156163

157164
const diffPercent = ((devResult.avg - localResult.avg) / devResult.avg) * 100;
158165
// Scale allowed difference relative to an optimistic 60fps target.

0 commit comments

Comments
 (0)