/ concept-collection / shtns-webgpu
Sign in
concept-collection / shtns-webgpu
shtns-webgpu / scripts / test-gpu.mjs
68 lines · 2.5 KBBlameHistoryRaw
1/**
2 * Headless GPU test runner: serves dist/, opens test.html in headless
3 * Chrome (falling back to the SwiftShader software WebGPU adapter when no
4 * hardware GPU is available), and reports the suite results.
5 *
6 * Run after `vite build`: node scripts/test-gpu.mjs
7 */
8import { createServer } from 'node:http';
9import { readFile } from 'node:fs/promises';
10import { extname, join } from 'node:path';
11import puppeteer from 'puppeteer-core';
13const DIST = new URL('../dist/', import.meta.url).pathname;
14const CHROME = process.env.CHROME_PATH ?? '/usr/bin/google-chrome';
15const MIME = {
16 '.html': 'text/html',
17 '.js': 'text/javascript',
18 '.css': 'text/css',
19 '.json': 'application/json',
20 '.wasm': 'application/wasm',
21};
23const server = createServer(async (req, res) => {
24 try {
25 const path = req.url === '/' ? '/index.html' : req.url.split('?')[0];
26 const data = await readFile(join(DIST, path));
27 res.writeHead(200, { 'content-type': MIME[extname(path)] ?? 'application/octet-stream' });
28 res.end(data);
29 } catch {
30 res.writeHead(404);
31 res.end('not found');
32 }
33});
34await new Promise((r) => server.listen(0, '127.0.0.1', r));
35const port = server.address().port;
37const flagSets = [
38 // hardware first, then SwiftShader (software) WebGPU
39 ['--headless=new', '--no-sandbox', '--enable-unsafe-webgpu', '--enable-features=Vulkan'],
40 ['--headless=new', '--no-sandbox', '--enable-unsafe-webgpu', '--use-webgpu-adapter=swiftshader', '--enable-unsafe-swiftshader'],
41];
43let final = null;
44for (const flags of flagSets) {
45 const browser = await puppeteer.launch({ executablePath: CHROME, args: flags });
46 try {
47 const page = await browser.newPage();
48 page.on('console', (msg) => console.log(` [page] ${msg.text()}`));
49 page.on('pageerror', (err) => console.log(` [pageerror] ${err.message}`));
50 await page.goto(`http://127.0.0.1:${port}/test.html`, { waitUntil: 'load' });
51 const results = await page.waitForFunction(() => window.__RESULTS__, { timeout: 600_000 });
52 final = await results.jsonValue();
53 } catch (e) {
54 console.error(`run with flags [${flags.join(' ')}] failed: ${e.message}`);
55 } finally {
56 await browser.close();
57 }
58 if (final && !final.fatal) break;
59 console.log('retrying with next flag set…');
61server.close();
63if (!final || final.fatal) {
64 console.error(`GPU tests could not run: ${final?.fatal ?? 'no results'}`);
65 process.exit(2);
67console.log(final.ok ? 'GPU SUITE: PASS' : 'GPU SUITE: FAIL');
68process.exit(final.ok ? 0 : 1);
moveopenescclose