From fec22b7b5ad7f662db8c7ba4ce30452a4391150c Mon Sep 17 00:00:00 2001 From: Kai Ninomiya Date: Fri, 16 Feb 2024 11:27:24 -0800 Subject: [PATCH 01/22] Generate Web Worker script for every test file This will be needed to launch Service Workers, which cannot be generated at runtime and cannot use dynamic import(). --- Gruntfile.js | 10 +- src/common/tools/gen_listings.ts | 56 ------------ .../tools/gen_listings_and_webworkers.ts | 91 +++++++++++++++++++ src/demo/webworker/.gitignore | 2 + src/manual/webworker/.gitignore | 2 + src/stress/webworker/.gitignore | 2 + src/unittests/webworker/.gitignore | 2 + src/webgpu/webworker/.gitignore | 2 + tools/gen_listings | 7 -- tools/gen_listings_and_webworkers | 8 ++ 10 files changed, 114 insertions(+), 68 deletions(-) delete mode 100644 src/common/tools/gen_listings.ts create mode 100644 src/common/tools/gen_listings_and_webworkers.ts create mode 100644 src/demo/webworker/.gitignore create mode 100644 src/manual/webworker/.gitignore create mode 100644 src/stress/webworker/.gitignore create mode 100644 src/unittests/webworker/.gitignore create mode 100644 src/webgpu/webworker/.gitignore delete mode 100755 tools/gen_listings create mode 100755 tools/gen_listings_and_webworkers diff --git a/Gruntfile.js b/Gruntfile.js index c354249f8b69..eba38704f3ee 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -24,9 +24,9 @@ module.exports = function (grunt) { cmd: 'node', args: ['tools/gen_version'], }, - 'generate-listings': { + 'generate-listings-and-webworkers': { cmd: 'node', - args: ['tools/gen_listings', 'gen/', ...kAllSuites.map(s => 'src/' + s)], + args: ['tools/gen_listings_and_webworkers', 'gen/', ...kAllSuites.map(s => 'src/' + s)], }, validate: { cmd: 'node', @@ -159,14 +159,14 @@ module.exports = function (grunt) { // Must run after generate-common and run:build-out. files: [ { expand: true, dest: 'out/', cwd: 'gen', src: 'common/internal/version.js' }, - { expand: true, dest: 'out/', cwd: 'gen', src: '*/listing.js' }, + { expand: true, dest: 'out/', cwd: 'gen', src: '*/**/*.js' }, ], }, 'gen-to-out-wpt': { // Must run after generate-common and run:build-out-wpt. files: [ { expand: true, dest: 'out-wpt/', cwd: 'gen', src: 'common/internal/version.js' }, - { expand: true, dest: 'out-wpt/', cwd: 'gen', src: 'webgpu/listing.js' }, + { expand: true, dest: 'out-wpt/', cwd: 'gen', src: 'webgpu/**/*.js' }, ], }, 'htmlfiles-to-out': { @@ -243,7 +243,7 @@ module.exports = function (grunt) { grunt.registerTask('generate-common', 'Generate files into gen/ and src/', [ 'run:generate-version', - 'run:generate-listings', + 'run:generate-listings-and-webworkers', 'run:generate-cache', ]); grunt.registerTask('build-standalone', 'Build out/ (no checks; run after generate-common)', [ diff --git a/src/common/tools/gen_listings.ts b/src/common/tools/gen_listings.ts deleted file mode 100644 index 032ebaa890f0..000000000000 --- a/src/common/tools/gen_listings.ts +++ /dev/null @@ -1,56 +0,0 @@ -import * as fs from 'fs'; -import * as path from 'path'; -import * as process from 'process'; - -import { crawl } from './crawl.js'; - -function usage(rc: number): void { - console.error(`Usage: tools/gen_listings [options] [OUT_DIR] [SUITE_DIRS...] - -For each suite in SUITE_DIRS, generate listings and write each listing.js -into OUT_DIR/{suite}/listing.js. Example: - tools/gen_listings gen/ src/unittests/ src/webgpu/ - -Options: - --help Print this message and exit. -`); - process.exit(rc); -} - -const argv = process.argv; -if (argv.indexOf('--help') !== -1) { - usage(0); -} - -{ - // Ignore old argument that is now the default - const i = argv.indexOf('--no-validate'); - if (i !== -1) { - argv.splice(i, 1); - } -} - -if (argv.length < 4) { - usage(0); -} - -const myself = 'src/common/tools/gen_listings.ts'; - -const outDir = argv[2]; - -for (const suiteDir of argv.slice(3)) { - // Run concurrently for each suite (might be a tiny bit more efficient) - void crawl(suiteDir, false).then(listing => { - const suite = path.basename(suiteDir); - const outFile = path.normalize(path.join(outDir, `${suite}/listing.js`)); - fs.mkdirSync(path.join(outDir, suite), { recursive: true }); - fs.writeFileSync( - outFile, - `\ -// AUTO-GENERATED - DO NOT EDIT. See ${myself}. - -export const listing = ${JSON.stringify(listing, undefined, 2)}; -` - ); - }); -} diff --git a/src/common/tools/gen_listings_and_webworkers.ts b/src/common/tools/gen_listings_and_webworkers.ts new file mode 100644 index 000000000000..ca1f9ff99049 --- /dev/null +++ b/src/common/tools/gen_listings_and_webworkers.ts @@ -0,0 +1,91 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import * as process from 'process'; + +import { crawl } from './crawl.js'; + +function usage(rc: number): void { + console.error(`Usage: tools/gen_listings [options] [OUT_DIR] [SUITE_DIRS...] + +For each suite in SUITE_DIRS, generate listings into OUT_DIR/{suite}/listing.js, +and generate Web Worker proxies in OUT_DIR/{suite}/webworker/**/*.worker.js for +every .spec.js file. (Note {suite}/webworker/ is reserved for this purpose.) + +Example: + tools/gen_listings gen/ src/unittests/ src/webgpu/ + +Options: + --help Print this message and exit. +`); + process.exit(rc); +} + +const argv = process.argv; +if (argv.indexOf('--help') !== -1) { + usage(0); +} + +{ + // Ignore old argument that is now the default + const i = argv.indexOf('--no-validate'); + if (i !== -1) { + argv.splice(i, 1); + } +} + +if (argv.length < 4) { + usage(0); +} + +const myself = 'src/common/tools/gen_listings.ts'; + +const outDir = argv[2]; + +for (const suiteDir of argv.slice(3)) { + // Run concurrently for each suite (might be a tiny bit more efficient) + void crawl(suiteDir, false).then(listing => { + const suite = path.basename(suiteDir); + + // Write listing.js + const outFile = path.normalize(path.join(outDir, `${suite}/listing.js`)); + fs.mkdirSync(path.join(outDir, suite), { recursive: true }); + fs.writeFileSync( + outFile, + `\ +// AUTO-GENERATED - DO NOT EDIT. See ${myself}. + +export const listing = ${JSON.stringify(listing, undefined, 2)}; +` + ); + + // Write suite/webworker/**/*.worker.js + for (const entry of listing) { + if ('readme' in entry) continue; + + const outFileDir = path.join( + outDir, + suite, + 'webworker', + ...entry.file.slice(0, entry.file.length - 1) + ); + const outFile = path.join(outDir, suite, 'webworker', ...entry.file) + '.worker.js'; + + const relPathToSuiteRoot = Array(entry.file.length).fill('..').join('/'); + + fs.mkdirSync(outFileDir, { recursive: true }); + fs.writeFileSync( + outFile, + `\ +// AUTO-GENERATED - DO NOT EDIT. See ${myself}. + +// oldG is a TestGroup object (defined in common/internal/test_group.ts). +import { g as oldG } from '${relPathToSuiteRoot}/${entry.file.join('/')}.spec.js'; + +// FIXME: Expose a proxied test interface. I think this can completely replace test_worker-worker.js +// (using this instead of that), but if not then hopefully it can at least share code with it. +console.log(oldG.iterate()); +` + ); + } + }); +} diff --git a/src/demo/webworker/.gitignore b/src/demo/webworker/.gitignore new file mode 100644 index 000000000000..8496277ad72e --- /dev/null +++ b/src/demo/webworker/.gitignore @@ -0,0 +1,2 @@ +# DIRECTORY RESERVED FOR GENERATED FILES. See gen_listings_and_webworkers. +* diff --git a/src/manual/webworker/.gitignore b/src/manual/webworker/.gitignore new file mode 100644 index 000000000000..8496277ad72e --- /dev/null +++ b/src/manual/webworker/.gitignore @@ -0,0 +1,2 @@ +# DIRECTORY RESERVED FOR GENERATED FILES. See gen_listings_and_webworkers. +* diff --git a/src/stress/webworker/.gitignore b/src/stress/webworker/.gitignore new file mode 100644 index 000000000000..8496277ad72e --- /dev/null +++ b/src/stress/webworker/.gitignore @@ -0,0 +1,2 @@ +# DIRECTORY RESERVED FOR GENERATED FILES. See gen_listings_and_webworkers. +* diff --git a/src/unittests/webworker/.gitignore b/src/unittests/webworker/.gitignore new file mode 100644 index 000000000000..8496277ad72e --- /dev/null +++ b/src/unittests/webworker/.gitignore @@ -0,0 +1,2 @@ +# DIRECTORY RESERVED FOR GENERATED FILES. See gen_listings_and_webworkers. +* diff --git a/src/webgpu/webworker/.gitignore b/src/webgpu/webworker/.gitignore new file mode 100644 index 000000000000..8496277ad72e --- /dev/null +++ b/src/webgpu/webworker/.gitignore @@ -0,0 +1,2 @@ +# DIRECTORY RESERVED FOR GENERATED FILES. See gen_listings_and_webworkers. +* diff --git a/tools/gen_listings b/tools/gen_listings deleted file mode 100755 index 6c25622423a1..000000000000 --- a/tools/gen_listings +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env node - -// Crawl a suite directory (e.g. src/webgpu/) to generate a listing.js containing -// the listing of test files in the suite. - -require('../src/common/tools/setup-ts-in-node.js'); -require('../src/common/tools/gen_listings.ts'); diff --git a/tools/gen_listings_and_webworkers b/tools/gen_listings_and_webworkers new file mode 100755 index 000000000000..285df3657d2a --- /dev/null +++ b/tools/gen_listings_and_webworkers @@ -0,0 +1,8 @@ +#!/usr/bin/env node + +// Crawl a suite directory (e.g. src/webgpu/) to generate a listing.js containing +// the listing of test files in the suite, and some generated test files +// (like suite/serviceworker/**/*.spec.js). + +require('../src/common/tools/setup-ts-in-node.js'); +require('../src/common/tools/gen_listings_and_webworkers.ts'); From 533afe44c8f9a52c9123c7111e9aa6811d91f4ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Beaufort?= Date: Mon, 19 Feb 2024 14:41:03 +0100 Subject: [PATCH 02/22] Add service worker support --- docs/intro/developing.md | 1 + src/common/runtime/helper/options.ts | 3 +- .../runtime/helper/test_worker-worker.ts | 2 +- src/common/runtime/helper/test_worker.ts | 49 ++++++++++++++++++ src/common/runtime/standalone.ts | 5 +- src/common/runtime/wpt.ts | 3 ++ src/common/tools/dev_server.ts | 8 ++- .../tools/gen_listings_and_webworkers.ts | 51 ++++++++++++++++++- src/webgpu/web_platform/worker/worker.spec.ts | 18 +++++++ src/webgpu/web_platform/worker/worker.ts | 2 +- .../web_platform/worker/worker_launcher.ts | 25 +++++++++ 11 files changed, 160 insertions(+), 7 deletions(-) diff --git a/docs/intro/developing.md b/docs/intro/developing.md index d8869f985b31..23da946b1e0c 100644 --- a/docs/intro/developing.md +++ b/docs/intro/developing.md @@ -58,6 +58,7 @@ The following url parameters change how the harness runs: - `debug=1` enables verbose debug logging from tests. - `worker=dedicated` runs the tests on a dedicated worker instead of the main thread. - `worker=shared` runs the tests on a shared worker instead of the main thread. +- `worker=service` runs the tests on a service worker instead of the main thread. - `power_preference=low-power` runs most tests passing `powerPreference: low-power` to `requestAdapter` - `power_preference=high-performance` runs most tests passing `powerPreference: high-performance` to `requestAdapter` diff --git a/src/common/runtime/helper/options.ts b/src/common/runtime/helper/options.ts index 60c2d1069181..67fd00372d39 100644 --- a/src/common/runtime/helper/options.ts +++ b/src/common/runtime/helper/options.ts @@ -25,7 +25,7 @@ export function optionString( * The possible options for the tests. */ export interface CTSOptions { - worker?: 'dedicated' | 'shared' | ''; + worker?: 'dedicated' | 'shared' | 'service' | ''; debug: boolean; compatibility: boolean; forceFallbackAdapter: boolean; @@ -68,6 +68,7 @@ export const kCTSOptionsInfo: OptionsInfos = { { value: '', description: 'no worker' }, { value: 'dedicated', description: 'dedicated worker' }, { value: 'shared', description: 'shared worker' }, + { value: 'service', description: 'service worker' }, ], }, debug: { description: 'show more info' }, diff --git a/src/common/runtime/helper/test_worker-worker.ts b/src/common/runtime/helper/test_worker-worker.ts index caf6e7a1bc17..25d9a3d33647 100644 --- a/src/common/runtime/helper/test_worker-worker.ts +++ b/src/common/runtime/helper/test_worker-worker.ts @@ -48,7 +48,7 @@ async function reportTestResults(this: MessagePort | Worker, ev: MessageEvent) { } self.onmessage = (ev: MessageEvent) => { - void reportTestResults.call(self, ev); + void reportTestResults.call(ev.source || self, ev); }; self.onconnect = (event: MessageEvent) => { diff --git a/src/common/runtime/helper/test_worker.ts b/src/common/runtime/helper/test_worker.ts index 9e2ec17efa95..9cca049c36c7 100644 --- a/src/common/runtime/helper/test_worker.ts +++ b/src/common/runtime/helper/test_worker.ts @@ -94,3 +94,52 @@ export class TestSharedWorker { rec.injectResult(workerResult); } } + +export class TestServiceWorker { + private readonly ctsOptions: CTSOptions; + private readonly resolvers = new Map void>(); + + constructor(ctsOptions?: CTSOptions) { + this.ctsOptions = { ...(ctsOptions || kDefaultCTSOptions), ...{ worker: 'service' } }; + } + + async run( + rec: TestCaseRecorder, + query: string, + expectations: TestQueryWithExpectation[] = [] + ): Promise { + const [suite, name] = query.split(":", 2); + const fileName = name.split(',').join('/'); + const serviceWorkerPath = `/out/${suite}/webworker/${fileName}.worker.js`; + + const registration = await navigator.serviceWorker.register(serviceWorkerPath, { + type: 'module', + scope: '/', + }); + await navigator.serviceWorker.ready; + + navigator.serviceWorker.onmessage = ev => { + const query: string = ev.data.query; + const result: TransferredTestCaseResult = ev.data.result; + if (result.logs) { + for (const l of result.logs) { + Object.setPrototypeOf(l, LogMessageWithStack.prototype); + } + } + this.resolvers.get(query)!(result as LiveTestCaseResult); + + // MAINTENANCE_TODO(kainino0x): update the Logger with this result (or don't have a logger and + // update the entire results JSON somehow at some point). + }; + + registration.active.postMessage({ + query, + expectations, + ctsOptions: this.ctsOptions, + }); + const serviceWorkerResult = await new Promise(resolve => { + this.resolvers.set(query, resolve); + }); + rec.injectResult(serviceWorkerResult); + } +} diff --git a/src/common/runtime/standalone.ts b/src/common/runtime/standalone.ts index fa938c55a276..62090ee5dc92 100644 --- a/src/common/runtime/standalone.ts +++ b/src/common/runtime/standalone.ts @@ -21,7 +21,7 @@ import { OptionsInfos, camelCaseToSnakeCase, } from './helper/options.js'; -import { TestDedicatedWorker, TestSharedWorker } from './helper/test_worker.js'; +import { TestDedicatedWorker, TestSharedWorker, TestServiceWorker } from './helper/test_worker.js'; const rootQuerySpec = 'webgpu:*'; let promptBeforeReload = false; @@ -66,6 +66,7 @@ setBaseResourcePath('../out/resources'); const dedicatedWorker = options.worker === 'dedicated' ? new TestDedicatedWorker(options) : undefined; const sharedWorker = options.worker === 'shared' ? new TestSharedWorker(options) : undefined; +const serviceWorker = options.worker === 'service' ? new TestServiceWorker(options) : undefined; const autoCloseOnPass = document.getElementById('autoCloseOnPass') as HTMLInputElement; const resultsVis = document.getElementById('resultsVis')!; @@ -182,6 +183,8 @@ function makeCaseHTML(t: TestTreeLeaf): VisualizedSubtree { await dedicatedWorker.run(rec, name); } else if (sharedWorker) { await sharedWorker.run(rec, name); + } else if (serviceWorker) { + await serviceWorker.run(rec, name); } else { await t.run(rec); } diff --git a/src/common/runtime/wpt.ts b/src/common/runtime/wpt.ts index aacd34b13e51..bba86fd1ba3d 100644 --- a/src/common/runtime/wpt.ts +++ b/src/common/runtime/wpt.ts @@ -34,6 +34,7 @@ void (async () => { const workerString = optionString('worker'); const dedicatedWorker = workerString === 'dedicated' ? new TestDedicatedWorker() : undefined; const sharedWorker = workerString === 'shared' ? new TestSharedWorker() : undefined; + const serviceWorker = workerString === 'service' ? new TestServiceWorker() : undefined; globalTestConfig.unrollConstEvalLoops = optionEnabled('unroll_const_eval_loops'); @@ -68,6 +69,8 @@ void (async () => { await dedicatedWorker.run(rec, name, expectations); } else if (sharedWorker) { await sharedWorker.run(rec, name, expectations); + } else if (serviceWorker) { + await serviceWorker.run(rec, name, expectations); } else { await testcase.run(rec, expectations); } diff --git a/src/common/tools/dev_server.ts b/src/common/tools/dev_server.ts index 57cb6a7ea4f6..535b99d9346e 100644 --- a/src/common/tools/dev_server.ts +++ b/src/common/tools/dev_server.ts @@ -150,14 +150,17 @@ app.get('/out/**/*.js', async (req, res, next) => { const tsUrl = jsUrl.replace(/\.js$/, '.ts'); if (compileCache.has(tsUrl)) { res.setHeader('Content-Type', 'application/javascript'); + res.setHeader('Service-Worker-Allowed', '/'); res.send(compileCache.get(tsUrl)); return; } - let absPath = path.join(srcDir, tsUrl); + // FIXME: I'm not sure if this is the way I should handle it... + const dir = jsUrl.endsWith('worker.js') ? path.resolve(srcDir, '../out') : srcDir; + let absPath = path.join(dir, tsUrl); if (!fs.existsSync(absPath)) { // The .ts file doesn't exist. Try .js file in case this is a .js/.d.ts pair. - absPath = path.join(srcDir, jsUrl); + absPath = path.join(dir, jsUrl); } try { @@ -166,6 +169,7 @@ app.get('/out/**/*.js', async (req, res, next) => { compileCache.set(tsUrl, result.code); res.setHeader('Content-Type', 'application/javascript'); + res.setHeader('Service-Worker-Allowed', '/'); res.send(result.code); } else { throw new Error(`Failed compile ${tsUrl}.`); diff --git a/src/common/tools/gen_listings_and_webworkers.ts b/src/common/tools/gen_listings_and_webworkers.ts index ca1f9ff99049..c46232f9c1ee 100644 --- a/src/common/tools/gen_listings_and_webworkers.ts +++ b/src/common/tools/gen_listings_and_webworkers.ts @@ -37,7 +37,7 @@ if (argv.length < 4) { usage(0); } -const myself = 'src/common/tools/gen_listings.ts'; +const myself = 'src/common/tools/gen_listings_and_webworkers.ts'; const outDir = argv[2]; @@ -84,6 +84,55 @@ import { g as oldG } from '${relPathToSuiteRoot}/${entry.file.join('/')}.spec.js // FIXME: Expose a proxied test interface. I think this can completely replace test_worker-worker.js // (using this instead of that), but if not then hopefully it can at least share code with it. console.log(oldG.iterate()); + +import { globalTestConfig } from '/out/common/framework/test_config.js'; +import { Logger } from '/out/common/internal/logging/logger.js'; +import { setDefaultRequestAdapterOptions } from '/out/common/util/navigator_gpu.js'; + +async function reportTestResults(ev) { + const query = ev.data.query; + const expectations = ev.data.expectations; + const ctsOptions = ev.data.ctsOptions; + + const { debug, unrollConstEvalLoops, powerPreference, compatibility } = ctsOptions; + globalTestConfig.unrollConstEvalLoops = unrollConstEvalLoops; + globalTestConfig.compatibility = compatibility; + + Logger.globalDebugMode = debug; + const log = new Logger(); + + if (powerPreference || compatibility) { + setDefaultRequestAdapterOptions({ + ...(powerPreference && { powerPreference }), + // MAINTENANCE_TODO: Change this to whatever the option ends up being + ...(compatibility && { compatibilityMode: true }), + }); + } + + // const testcases = Array.from(await loader.loadCases(parseQuery(query))); + // assert(testcases.length === 1, 'worker query resulted in != 1 cases'); + + // const testcase = testcases[0]; + const testcase = { query }; // FIXME! I failed to figure out how to get a testcase from oldG and query ;( + const [rec, result] = log.record(testcase.query.toString()); + // await testcase.run(rec, expectations); + result.status = 'pass'; // FIXME + result.timems = 42; // FIXME + this.postMessage({ query, result }); + +} + +self.onmessage = (ev) => { + void reportTestResults.call(ev.source || self, ev); +}; + +self.onconnect = (event) => { + const port = event.ports[0]; + + port.onmessage = (ev) => { + void reportTestResults.call(port, ev); + }; +}; ` ); } diff --git a/src/webgpu/web_platform/worker/worker.spec.ts b/src/webgpu/web_platform/worker/worker.spec.ts index 0f34a58ddaa5..9b93a5d5339e 100644 --- a/src/webgpu/web_platform/worker/worker.spec.ts +++ b/src/webgpu/web_platform/worker/worker.spec.ts @@ -51,3 +51,21 @@ g.test('shared_worker') const result = await launchSharedWorker(); assert(result.error === undefined, `should be no error from worker but was: ${result.error}`); }); + +g.test('service_worker') + .desc(`test WebGPU is available in service workers and check for basic functionality`) + .fn(async t => { + if (isNode()) { + t.skip('node does not support 100% compatible workers'); + return; + } + // Note: we load worker_launcher dynamically because ts-node support + // is using commonjs which doesn't support import.meta. Further, + // we need to put the url in a string add pass the string to import + // otherwise typescript tries to parse the file which again, fails. + // worker_launcher.js is excluded in node.tsconfig.json. + const url = './worker_launcher.js'; + const { launchServiceWorker } = await import(url); + const result = await launchServiceWorker(); + assert(result.error === undefined, `should be no error from worker but was: ${result.error}`); + }); diff --git a/src/webgpu/web_platform/worker/worker.ts b/src/webgpu/web_platform/worker/worker.ts index f3c907a4118a..033473d63a97 100644 --- a/src/webgpu/web_platform/worker/worker.ts +++ b/src/webgpu/web_platform/worker/worker.ts @@ -87,7 +87,7 @@ async function reportTestResults(this: MessagePort | Worker, ev: MessageEvent) { } self.onmessage = (ev: MessageEvent) => { - void reportTestResults.call(self, ev); + void reportTestResults.call(ev.source || self, ev); }; self.onconnect = (event: MessageEvent) => { diff --git a/src/webgpu/web_platform/worker/worker_launcher.ts b/src/webgpu/web_platform/worker/worker_launcher.ts index 0487e4ad38b4..8ea652ac0efe 100644 --- a/src/webgpu/web_platform/worker/worker_launcher.ts +++ b/src/webgpu/web_platform/worker/worker_launcher.ts @@ -33,3 +33,28 @@ export async function launchSharedWorker() { }); return await promise; } + +export async function launchServiceWorker() { + const selfPath = import.meta.url; + const selfPathDir = selfPath.substring(0, selfPath.lastIndexOf('/')); + const serviceWorkerPath = selfPathDir + '/worker.js'; + const registration = await navigator.serviceWorker.register(serviceWorkerPath, { + type: 'module', + scope: '/', + }); + await navigator.serviceWorker.ready; + + const promise = new Promise(resolve => { + navigator.serviceWorker.addEventListener( + 'message', + ev => { + resolve(ev.data as TestResult); + }, + { once: true } + ); + }); + registration.active.postMessage({ + defaultRequestAdapterOptions: getDefaultRequestAdapterOptions(), + }); + return await promise; +} From 20444d0cd52bd393a51c3b9ac202a7dd01f4ebeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Beaufort?= Date: Mon, 26 Feb 2024 14:25:20 +0100 Subject: [PATCH 03/22] Update wpt.ts --- src/common/runtime/wpt.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/runtime/wpt.ts b/src/common/runtime/wpt.ts index bba86fd1ba3d..56ff9649e045 100644 --- a/src/common/runtime/wpt.ts +++ b/src/common/runtime/wpt.ts @@ -9,7 +9,7 @@ import { parseExpectationsForTestQuery, relativeQueryString } from '../internal/ import { assert } from '../util/util.js'; import { optionEnabled, optionString } from './helper/options.js'; -import { TestDedicatedWorker, TestSharedWorker } from './helper/test_worker.js'; +import { TestDedicatedWorker, TestServiceWorker, TestSharedWorker } from './helper/test_worker.js'; // testharness.js API (https://web-platform-tests.org/writing-tests/testharness-api.html) declare interface WptTestObject { From 23f0a474f25b05f44a9fa5040459e7fada56f6b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Beaufort?= Date: Mon, 4 Mar 2024 13:52:32 +0100 Subject: [PATCH 04/22] Run tests --- src/common/runtime/helper/test_worker.ts | 7 +- src/common/tools/dev_server.ts | 2 +- .../tools/gen_listings_and_webworkers.ts | 33 +-- src/resources/cache/hashes.json | 210 +++++++++--------- .../cache/webgpu/shader/execution/bitcast.bin | Bin 2221448 -> 2221448 bytes src/webgpu/listing_meta.json | 1 + .../web_platform/worker/worker_launcher.ts | 5 +- 7 files changed, 131 insertions(+), 127 deletions(-) diff --git a/src/common/runtime/helper/test_worker.ts b/src/common/runtime/helper/test_worker.ts index 9cca049c36c7..7b5e85a0bafa 100644 --- a/src/common/runtime/helper/test_worker.ts +++ b/src/common/runtime/helper/test_worker.ts @@ -108,7 +108,7 @@ export class TestServiceWorker { query: string, expectations: TestQueryWithExpectation[] = [] ): Promise { - const [suite, name] = query.split(":", 2); + const [suite, name] = query.split(':', 2); const fileName = name.split(',').join('/'); const serviceWorkerPath = `/out/${suite}/webworker/${fileName}.worker.js`; @@ -116,7 +116,7 @@ export class TestServiceWorker { type: 'module', scope: '/', }); - await navigator.serviceWorker.ready; + await registration.update(); navigator.serviceWorker.onmessage = ev => { const query: string = ev.data.query; @@ -132,13 +132,14 @@ export class TestServiceWorker { // update the entire results JSON somehow at some point). }; - registration.active.postMessage({ + registration.active?.postMessage({ query, expectations, ctsOptions: this.ctsOptions, }); const serviceWorkerResult = await new Promise(resolve => { this.resolvers.set(query, resolve); + void registration.unregister(); }); rec.injectResult(serviceWorkerResult); } diff --git a/src/common/tools/dev_server.ts b/src/common/tools/dev_server.ts index 535b99d9346e..2845a2375524 100644 --- a/src/common/tools/dev_server.ts +++ b/src/common/tools/dev_server.ts @@ -155,7 +155,7 @@ app.get('/out/**/*.js', async (req, res, next) => { return; } - // FIXME: I'm not sure if this is the way I should handle it... + // I'm not sure if this is the way I should handle it... const dir = jsUrl.endsWith('worker.js') ? path.resolve(srcDir, '../out') : srcDir; let absPath = path.join(dir, tsUrl); if (!fs.existsSync(absPath)) { diff --git a/src/common/tools/gen_listings_and_webworkers.ts b/src/common/tools/gen_listings_and_webworkers.ts index c46232f9c1ee..b922cb763fb8 100644 --- a/src/common/tools/gen_listings_and_webworkers.ts +++ b/src/common/tools/gen_listings_and_webworkers.ts @@ -78,16 +78,15 @@ export const listing = ${JSON.stringify(listing, undefined, 2)}; `\ // AUTO-GENERATED - DO NOT EDIT. See ${myself}. -// oldG is a TestGroup object (defined in common/internal/test_group.ts). -import { g as oldG } from '${relPathToSuiteRoot}/${entry.file.join('/')}.spec.js'; - -// FIXME: Expose a proxied test interface. I think this can completely replace test_worker-worker.js -// (using this instead of that), but if not then hopefully it can at least share code with it. -console.log(oldG.iterate()); +// g is a TestGroup object (defined in common/internal/test_group.ts). +import { g } from '${relPathToSuiteRoot}/${entry.file.join('/')}.spec.js'; import { globalTestConfig } from '/out/common/framework/test_config.js'; import { Logger } from '/out/common/internal/logging/logger.js'; import { setDefaultRequestAdapterOptions } from '/out/common/util/navigator_gpu.js'; +import { parseQuery } from '/out/common/internal/query/parseQuery.js'; +import { comparePublicParamsPaths, Ordering } from '/out/common/internal/query/compare.js'; +import { assert } from '/out/common/util/util.js'; async function reportTestResults(ev) { const query = ev.data.query; @@ -109,17 +108,19 @@ async function reportTestResults(ev) { }); } - // const testcases = Array.from(await loader.loadCases(parseQuery(query))); - // assert(testcases.length === 1, 'worker query resulted in != 1 cases'); - - // const testcase = testcases[0]; - const testcase = { query }; // FIXME! I failed to figure out how to get a testcase from oldG and query ;( - const [rec, result] = log.record(testcase.query.toString()); - // await testcase.run(rec, expectations); - result.status = 'pass'; // FIXME - result.timems = 42; // FIXME + const testQuerySingleCase = parseQuery(query); + let testcase = null; + for (const t of g.iterate()) { + for (const c of t.iterate(testQuerySingleCase.params)) { + if (comparePublicParamsPaths(c.id.params, testQuerySingleCase.params) === Ordering.Equal) { + testcase = c; + } + } + } + assert(testcase); + const [rec, result] = log.record(query); + await testcase.run(rec, testQuerySingleCase, expectations); this.postMessage({ query, result }); - } self.onmessage = (ev) => { diff --git a/src/resources/cache/hashes.json b/src/resources/cache/hashes.json index 9476d8431f41..5a5316cda1f6 100644 --- a/src/resources/cache/hashes.json +++ b/src/resources/cache/hashes.json @@ -1,107 +1,107 @@ { - "webgpu/shader/execution/binary/af_addition.bin": "38b261fa", - "webgpu/shader/execution/binary/af_logical.bin": "a483b968", - "webgpu/shader/execution/binary/af_division.bin": "ec39b0da", - "webgpu/shader/execution/binary/af_matrix_addition.bin": "ca1373a8", - "webgpu/shader/execution/binary/af_matrix_subtraction.bin": "406d99af", - "webgpu/shader/execution/binary/af_multiplication.bin": "2eb6d50d", - "webgpu/shader/execution/binary/af_remainder.bin": "e2b6b21", - "webgpu/shader/execution/binary/af_subtraction.bin": "84794350", - "webgpu/shader/execution/binary/f16_addition.bin": "19e8823d", - "webgpu/shader/execution/binary/f16_logical.bin": "b89ca9b9", - "webgpu/shader/execution/binary/f16_division.bin": "6dc4b748", - "webgpu/shader/execution/binary/f16_matrix_addition.bin": "7533842", - "webgpu/shader/execution/binary/f16_matrix_matrix_multiplication.bin": "2d799920", - "webgpu/shader/execution/binary/f16_matrix_scalar_multiplication.bin": "44e3b295", - "webgpu/shader/execution/binary/f16_matrix_subtraction.bin": "412f0911", - "webgpu/shader/execution/binary/f16_matrix_vector_multiplication.bin": "a231201b", - "webgpu/shader/execution/binary/f16_multiplication.bin": "94b11030", - "webgpu/shader/execution/binary/f16_remainder.bin": "de68a200", - "webgpu/shader/execution/binary/f16_subtraction.bin": "f308327a", - "webgpu/shader/execution/binary/f32_addition.bin": "c87c8c08", - "webgpu/shader/execution/binary/f32_logical.bin": "c7370c09", - "webgpu/shader/execution/binary/f32_division.bin": "34ce65ae", - "webgpu/shader/execution/binary/f32_matrix_addition.bin": "f3808d0c", - "webgpu/shader/execution/binary/f32_matrix_matrix_multiplication.bin": "e33e7fe5", - "webgpu/shader/execution/binary/f32_matrix_scalar_multiplication.bin": "41091ebf", - "webgpu/shader/execution/binary/f32_matrix_subtraction.bin": "37ccb101", - "webgpu/shader/execution/binary/f32_matrix_vector_multiplication.bin": "4d67866", - "webgpu/shader/execution/binary/f32_multiplication.bin": "5d85a36c", - "webgpu/shader/execution/binary/f32_remainder.bin": "62f591b2", - "webgpu/shader/execution/binary/f32_subtraction.bin": "60fc275a", - "webgpu/shader/execution/binary/i32_arithmetic.bin": "a0b0a016", - "webgpu/shader/execution/binary/i32_comparison.bin": "f3d9b3f9", - "webgpu/shader/execution/binary/u32_arithmetic.bin": "16e32fd", - "webgpu/shader/execution/binary/u32_comparison.bin": "da33cc5d", - "webgpu/shader/execution/abs.bin": "1ead834c", - "webgpu/shader/execution/acos.bin": "e25802ba", - "webgpu/shader/execution/acosh.bin": "2321726f", - "webgpu/shader/execution/asin.bin": "d554a73b", - "webgpu/shader/execution/asinh.bin": "d2bdb21b", - "webgpu/shader/execution/atan.bin": "eb6476f3", - "webgpu/shader/execution/atan2.bin": "cf15e7fa", - "webgpu/shader/execution/atanh.bin": "6c57cc3", - "webgpu/shader/execution/bitcast.bin": "a25e9714", - "webgpu/shader/execution/ceil.bin": "8d120ea3", - "webgpu/shader/execution/clamp.bin": "a762ef58", - "webgpu/shader/execution/cos.bin": "a859da89", - "webgpu/shader/execution/cosh.bin": "86abdd85", - "webgpu/shader/execution/cross.bin": "e4556729", - "webgpu/shader/execution/degrees.bin": "1fa19a41", - "webgpu/shader/execution/determinant.bin": "108c3d65", - "webgpu/shader/execution/distance.bin": "77a1baa6", - "webgpu/shader/execution/dot.bin": "d4ac2e8a", - "webgpu/shader/execution/exp.bin": "15539afd", - "webgpu/shader/execution/exp2.bin": "7f6a8523", - "webgpu/shader/execution/faceForward.bin": "e7b35f43", - "webgpu/shader/execution/floor.bin": "b26656ca", - "webgpu/shader/execution/fma.bin": "5a70c683", - "webgpu/shader/execution/fract.bin": "23c0d5ec", - "webgpu/shader/execution/frexp.bin": "d28e66be", - "webgpu/shader/execution/inverseSqrt.bin": "9f297854", - "webgpu/shader/execution/ldexp.bin": "638db0c7", - "webgpu/shader/execution/length.bin": "7d237c62", - "webgpu/shader/execution/log.bin": "70720bf0", - "webgpu/shader/execution/log2.bin": "93a309be", - "webgpu/shader/execution/max.bin": "36eb4779", - "webgpu/shader/execution/min.bin": "ca772bf1", - "webgpu/shader/execution/mix.bin": "ecbf61ae", - "webgpu/shader/execution/modf.bin": "6ddea900", - "webgpu/shader/execution/normalize.bin": "d3e47c61", - "webgpu/shader/execution/pack2x16float.bin": "e6859c1a", - "webgpu/shader/execution/pow.bin": "a58be71c", - "webgpu/shader/execution/quantizeToF16.bin": "eca85bca", - "webgpu/shader/execution/radians.bin": "a216c9aa", - "webgpu/shader/execution/reflect.bin": "ebce9830", - "webgpu/shader/execution/refract.bin": "59d1e5d6", - "webgpu/shader/execution/round.bin": "9389a090", - "webgpu/shader/execution/saturate.bin": "7ca4b681", - "webgpu/shader/execution/sign.bin": "1f4eeb34", - "webgpu/shader/execution/sin.bin": "a1e234b4", - "webgpu/shader/execution/sinh.bin": "1a62054b", - "webgpu/shader/execution/smoothstep.bin": "d5824fd6", - "webgpu/shader/execution/sqrt.bin": "66f21d02", - "webgpu/shader/execution/step.bin": "310cb6c7", - "webgpu/shader/execution/tan.bin": "1e26f533", - "webgpu/shader/execution/tanh.bin": "4c546d1c", - "webgpu/shader/execution/transpose.bin": "7bef2494", - "webgpu/shader/execution/trunc.bin": "e72535eb", - "webgpu/shader/execution/unpack2x16float.bin": "593d88c6", - "webgpu/shader/execution/unpack2x16snorm.bin": "9ebd3e40", - "webgpu/shader/execution/unpack2x16unorm.bin": "83a36fa9", - "webgpu/shader/execution/unpack4x8snorm.bin": "41b12606", - "webgpu/shader/execution/unpack4x8unorm.bin": "96f1850b", - "webgpu/shader/execution/unary/af_arithmetic.bin": "6fa1d84a", - "webgpu/shader/execution/unary/af_assignment.bin": "98c8f82a", - "webgpu/shader/execution/unary/bool_conversion.bin": "dd71f171", - "webgpu/shader/execution/unary/f16_arithmetic.bin": "2f2d38fc", - "webgpu/shader/execution/unary/f16_conversion.bin": "70c94538", - "webgpu/shader/execution/unary/f32_arithmetic.bin": "db90c01c", - "webgpu/shader/execution/unary/f32_conversion.bin": "81912140", - "webgpu/shader/execution/unary/i32_arithmetic.bin": "c69716e2", - "webgpu/shader/execution/unary/i32_conversion.bin": "83218e69", - "webgpu/shader/execution/unary/u32_conversion.bin": "8f5bad00", - "webgpu/shader/execution/unary/ai_assignment.bin": "c7e6ac33", - "webgpu/shader/execution/binary/ai_arithmetic.bin": "81c11ec2", - "webgpu/shader/execution/unary/ai_arithmetic.bin": "3d27dc97" + "webgpu/shader/execution/binary/af_addition.bin": "fc43d206", + "webgpu/shader/execution/binary/af_logical.bin": "3dc912ac", + "webgpu/shader/execution/binary/af_division.bin": "6cbdaf09", + "webgpu/shader/execution/binary/af_matrix_addition.bin": "d61fe049", + "webgpu/shader/execution/binary/af_matrix_subtraction.bin": "16d18276", + "webgpu/shader/execution/binary/af_multiplication.bin": "ce2a0e9e", + "webgpu/shader/execution/binary/af_remainder.bin": "4032e3cf", + "webgpu/shader/execution/binary/af_subtraction.bin": "67a1c189", + "webgpu/shader/execution/binary/f16_addition.bin": "3edd84a3", + "webgpu/shader/execution/binary/f16_logical.bin": "adcc36e9", + "webgpu/shader/execution/binary/f16_division.bin": "81168258", + "webgpu/shader/execution/binary/f16_matrix_addition.bin": "3497729d", + "webgpu/shader/execution/binary/f16_matrix_matrix_multiplication.bin": "767e22c7", + "webgpu/shader/execution/binary/f16_matrix_scalar_multiplication.bin": "356acec0", + "webgpu/shader/execution/binary/f16_matrix_subtraction.bin": "ed00c0e4", + "webgpu/shader/execution/binary/f16_matrix_vector_multiplication.bin": "f089b873", + "webgpu/shader/execution/binary/f16_multiplication.bin": "4675c758", + "webgpu/shader/execution/binary/f16_remainder.bin": "5ea2af46", + "webgpu/shader/execution/binary/f16_subtraction.bin": "a7962472", + "webgpu/shader/execution/binary/f32_addition.bin": "ef624c29", + "webgpu/shader/execution/binary/f32_logical.bin": "68c1e846", + "webgpu/shader/execution/binary/f32_division.bin": "cc886305", + "webgpu/shader/execution/binary/f32_matrix_addition.bin": "b3bab14a", + "webgpu/shader/execution/binary/f32_matrix_matrix_multiplication.bin": "afccd9d5", + "webgpu/shader/execution/binary/f32_matrix_scalar_multiplication.bin": "c8a022a1", + "webgpu/shader/execution/binary/f32_matrix_subtraction.bin": "b0db93fb", + "webgpu/shader/execution/binary/f32_matrix_vector_multiplication.bin": "d90fbe21", + "webgpu/shader/execution/binary/f32_multiplication.bin": "693597cf", + "webgpu/shader/execution/binary/f32_remainder.bin": "fe630a4b", + "webgpu/shader/execution/binary/f32_subtraction.bin": "e3409ba2", + "webgpu/shader/execution/binary/i32_arithmetic.bin": "bd8d0b9b", + "webgpu/shader/execution/binary/i32_comparison.bin": "aec6e622", + "webgpu/shader/execution/binary/u32_arithmetic.bin": "f5907c7e", + "webgpu/shader/execution/binary/u32_comparison.bin": "7160f1c7", + "webgpu/shader/execution/abs.bin": "c884966", + "webgpu/shader/execution/acos.bin": "3e371b22", + "webgpu/shader/execution/acosh.bin": "25b25012", + "webgpu/shader/execution/asin.bin": "75d5b677", + "webgpu/shader/execution/asinh.bin": "92fe4ad3", + "webgpu/shader/execution/atan.bin": "5a7834a4", + "webgpu/shader/execution/atan2.bin": "79487bb", + "webgpu/shader/execution/atanh.bin": "804ad33f", + "webgpu/shader/execution/bitcast.bin": "69a86c70", + "webgpu/shader/execution/ceil.bin": "46bca9a0", + "webgpu/shader/execution/clamp.bin": "620739ae", + "webgpu/shader/execution/cos.bin": "bd7467e4", + "webgpu/shader/execution/cosh.bin": "315aad98", + "webgpu/shader/execution/cross.bin": "d9a91811", + "webgpu/shader/execution/degrees.bin": "27df6eb0", + "webgpu/shader/execution/determinant.bin": "67380eba", + "webgpu/shader/execution/distance.bin": "91d94128", + "webgpu/shader/execution/dot.bin": "3644a88a", + "webgpu/shader/execution/exp.bin": "786e68bc", + "webgpu/shader/execution/exp2.bin": "454ee68d", + "webgpu/shader/execution/faceForward.bin": "625903d3", + "webgpu/shader/execution/floor.bin": "db4c92f7", + "webgpu/shader/execution/fma.bin": "b049ac43", + "webgpu/shader/execution/fract.bin": "84ce9ec3", + "webgpu/shader/execution/frexp.bin": "5320c481", + "webgpu/shader/execution/inverseSqrt.bin": "7aeff2c0", + "webgpu/shader/execution/ldexp.bin": "71b3930f", + "webgpu/shader/execution/length.bin": "e96b503a", + "webgpu/shader/execution/log.bin": "eba7ec7d", + "webgpu/shader/execution/log2.bin": "54ddf967", + "webgpu/shader/execution/max.bin": "a83a582a", + "webgpu/shader/execution/min.bin": "7c2811c1", + "webgpu/shader/execution/mix.bin": "9aa0305f", + "webgpu/shader/execution/modf.bin": "ca3173c2", + "webgpu/shader/execution/normalize.bin": "3c3a347f", + "webgpu/shader/execution/pack2x16float.bin": "73ddf92f", + "webgpu/shader/execution/pow.bin": "d2c3fd97", + "webgpu/shader/execution/quantizeToF16.bin": "ad3587f0", + "webgpu/shader/execution/radians.bin": "d5f10c52", + "webgpu/shader/execution/reflect.bin": "219e2df", + "webgpu/shader/execution/refract.bin": "fa841745", + "webgpu/shader/execution/round.bin": "74f863ec", + "webgpu/shader/execution/saturate.bin": "457fd49d", + "webgpu/shader/execution/sign.bin": "e44d954c", + "webgpu/shader/execution/sin.bin": "67bac1fd", + "webgpu/shader/execution/sinh.bin": "e37cb02b", + "webgpu/shader/execution/smoothstep.bin": "d279bc42", + "webgpu/shader/execution/sqrt.bin": "551939af", + "webgpu/shader/execution/step.bin": "72cf60af", + "webgpu/shader/execution/tan.bin": "f632f032", + "webgpu/shader/execution/tanh.bin": "72c375cb", + "webgpu/shader/execution/transpose.bin": "e968d355", + "webgpu/shader/execution/trunc.bin": "16f79aa5", + "webgpu/shader/execution/unpack2x16float.bin": "c85da768", + "webgpu/shader/execution/unpack2x16snorm.bin": "3f3dbc81", + "webgpu/shader/execution/unpack2x16unorm.bin": "2862cb20", + "webgpu/shader/execution/unpack4x8snorm.bin": "b4c90280", + "webgpu/shader/execution/unpack4x8unorm.bin": "ab1a627b", + "webgpu/shader/execution/unary/af_arithmetic.bin": "67d2b7eb", + "webgpu/shader/execution/unary/af_assignment.bin": "7964e983", + "webgpu/shader/execution/unary/bool_conversion.bin": "349303eb", + "webgpu/shader/execution/unary/f16_arithmetic.bin": "95908291", + "webgpu/shader/execution/unary/f16_conversion.bin": "df34e3f9", + "webgpu/shader/execution/unary/f32_arithmetic.bin": "dea317cd", + "webgpu/shader/execution/unary/f32_conversion.bin": "fb0ff55a", + "webgpu/shader/execution/unary/i32_arithmetic.bin": "d1b09384", + "webgpu/shader/execution/unary/i32_conversion.bin": "7ae3fc76", + "webgpu/shader/execution/unary/u32_conversion.bin": "a1c35c09", + "webgpu/shader/execution/unary/ai_assignment.bin": "bde2f00d", + "webgpu/shader/execution/binary/ai_arithmetic.bin": "f99fb5b7", + "webgpu/shader/execution/unary/ai_arithmetic.bin": "5784ac67" } \ No newline at end of file diff --git a/src/resources/cache/webgpu/shader/execution/bitcast.bin b/src/resources/cache/webgpu/shader/execution/bitcast.bin index d3954903ac89afcfbe5049a356005ed02cf10aae..ab435f3902a6e2124845cfba3625a2184be02b02 100644 GIT binary patch delta 159 zcmWN=xe!UpJO`QFS^|H)F+Us={6S!U^M yV@55L7K=7dJk#NYSGx4*GhoPwH^xkuGGop=A1qk1V$COCeDlMGExVtVe%}s}89n6y delta 159 zcmWN=OA3Nu6o65*G|PPFD(resolve => { navigator.serviceWorker.addEventListener( 'message', ev => { resolve(ev.data as TestResult); + void registration.unregister(); }, { once: true } ); }); - registration.active.postMessage({ + registration.active?.postMessage({ defaultRequestAdapterOptions: getDefaultRequestAdapterOptions(), }); return await promise; From 675f6ada8a0842f80e13ce5f9413cede15710950 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Beaufort?= Date: Wed, 6 Mar 2024 11:05:53 +0100 Subject: [PATCH 05/22] Address kainino0x feedback --- src/common/internal/query/compare.ts | 2 +- src/common/runtime/helper/test_worker.ts | 85 +++---- src/common/runtime/helper/wrap_for_worker.ts | 52 +++++ .../tools/gen_listings_and_webworkers.ts | 55 +---- src/resources/cache/hashes.json | 210 +++++++++--------- src/webgpu/web_platform/worker/worker.spec.ts | 36 +-- 6 files changed, 201 insertions(+), 239 deletions(-) create mode 100644 src/common/runtime/helper/wrap_for_worker.ts diff --git a/src/common/internal/query/compare.ts b/src/common/internal/query/compare.ts index a9419b87c196..39b263f4deeb 100644 --- a/src/common/internal/query/compare.ts +++ b/src/common/internal/query/compare.ts @@ -58,7 +58,7 @@ function compareOneLevel(ordering: Ordering, aIsBig: boolean, bIsBig: boolean): return Ordering.Unordered; } -function comparePaths(a: readonly string[], b: readonly string[]): Ordering { +export function comparePaths(a: readonly string[], b: readonly string[]): Ordering { const shorter = Math.min(a.length, b.length); for (let i = 0; i < shorter; ++i) { diff --git a/src/common/runtime/helper/test_worker.ts b/src/common/runtime/helper/test_worker.ts index 7b5e85a0bafa..174a9170a0dd 100644 --- a/src/common/runtime/helper/test_worker.ts +++ b/src/common/runtime/helper/test_worker.ts @@ -5,30 +5,39 @@ import { TestQueryWithExpectation } from '../../internal/query/query.js'; import { CTSOptions, kDefaultCTSOptions } from './options.js'; -export class TestDedicatedWorker { - private readonly ctsOptions: CTSOptions; +class TestBaseWorker { + protected readonly ctsOptions: CTSOptions; + protected readonly resolvers = new Map void>(); + + constructor(worker: CTSOptions['worker'], ctsOptions?: CTSOptions) { + this.ctsOptions = { ...(ctsOptions || kDefaultCTSOptions), ...{ worker } }; + } + + onmessage(ev: MessageEvent) { + const query: string = ev.data.query; + const result: TransferredTestCaseResult = ev.data.result; + if (result.logs) { + for (const l of result.logs) { + Object.setPrototypeOf(l, LogMessageWithStack.prototype); + } + } + this.resolvers.get(query)!(result as LiveTestCaseResult); + + // MAINTENANCE_TODO(kainino0x): update the Logger with this result (or don't have a logger and + // update the entire results JSON somehow at some point). + } +} + +export class TestDedicatedWorker extends TestBaseWorker { private readonly worker: Worker; - private readonly resolvers = new Map void>(); constructor(ctsOptions?: CTSOptions) { - this.ctsOptions = { ...(ctsOptions || kDefaultCTSOptions), ...{ worker: 'dedicated' } }; + super('dedicated', ctsOptions); const selfPath = import.meta.url; const selfPathDir = selfPath.substring(0, selfPath.lastIndexOf('/')); const workerPath = selfPathDir + '/test_worker-worker.js'; this.worker = new Worker(workerPath, { type: 'module' }); - this.worker.onmessage = ev => { - const query: string = ev.data.query; - const result: TransferredTestCaseResult = ev.data.result; - if (result.logs) { - for (const l of result.logs) { - Object.setPrototypeOf(l, LogMessageWithStack.prototype); - } - } - this.resolvers.get(query)!(result as LiveTestCaseResult); - - // MAINTENANCE_TODO(kainino0x): update the Logger with this result (or don't have a logger and - // update the entire results JSON somehow at some point). - }; + this.worker.onmessage = ev => this.onmessage(ev); } async run( @@ -50,32 +59,18 @@ export class TestDedicatedWorker { export class TestWorker extends TestDedicatedWorker {} -export class TestSharedWorker { - private readonly ctsOptions: CTSOptions; +export class TestSharedWorker extends TestBaseWorker { private readonly port: MessagePort; - private readonly resolvers = new Map void>(); constructor(ctsOptions?: CTSOptions) { - this.ctsOptions = { ...(ctsOptions || kDefaultCTSOptions), ...{ worker: 'shared' } }; + super('shared', ctsOptions); const selfPath = import.meta.url; const selfPathDir = selfPath.substring(0, selfPath.lastIndexOf('/')); const workerPath = selfPathDir + '/test_worker-worker.js'; const worker = new SharedWorker(workerPath, { type: 'module' }); this.port = worker.port; this.port.start(); - this.port.onmessage = ev => { - const query: string = ev.data.query; - const result: TransferredTestCaseResult = ev.data.result; - if (result.logs) { - for (const l of result.logs) { - Object.setPrototypeOf(l, LogMessageWithStack.prototype); - } - } - this.resolvers.get(query)!(result as LiveTestCaseResult); - - // MAINTENANCE_TODO(kainino0x): update the Logger with this result (or don't have a logger and - // update the entire results JSON somehow at some point). - }; + this.port.onmessage = ev => this.onmessage(ev); } async run( @@ -95,12 +90,9 @@ export class TestSharedWorker { } } -export class TestServiceWorker { - private readonly ctsOptions: CTSOptions; - private readonly resolvers = new Map void>(); - +export class TestServiceWorker extends TestBaseWorker { constructor(ctsOptions?: CTSOptions) { - this.ctsOptions = { ...(ctsOptions || kDefaultCTSOptions), ...{ worker: 'service' } }; + super('service', ctsOptions); } async run( @@ -117,20 +109,7 @@ export class TestServiceWorker { scope: '/', }); await registration.update(); - - navigator.serviceWorker.onmessage = ev => { - const query: string = ev.data.query; - const result: TransferredTestCaseResult = ev.data.result; - if (result.logs) { - for (const l of result.logs) { - Object.setPrototypeOf(l, LogMessageWithStack.prototype); - } - } - this.resolvers.get(query)!(result as LiveTestCaseResult); - - // MAINTENANCE_TODO(kainino0x): update the Logger with this result (or don't have a logger and - // update the entire results JSON somehow at some point). - }; + navigator.serviceWorker.onmessage = ev => this.onmessage(ev); registration.active?.postMessage({ query, diff --git a/src/common/runtime/helper/wrap_for_worker.ts b/src/common/runtime/helper/wrap_for_worker.ts new file mode 100644 index 000000000000..b804ae6088e5 --- /dev/null +++ b/src/common/runtime/helper/wrap_for_worker.ts @@ -0,0 +1,52 @@ +import { Fixture } from '../../framework/fixture'; +import { globalTestConfig } from '../../framework/test_config.js'; +import { Logger } from '../../internal/logging/logger.js'; +import { comparePaths, comparePublicParamsPaths, Ordering } from '../../internal/query/compare.js'; +import { parseQuery } from '../../internal/query/parseQuery.js'; +import { TestQuerySingleCase, TestQueryWithExpectation } from '../../internal/query/query.js'; +import { TestGroup } from '../../internal/test_group.js'; +import { setDefaultRequestAdapterOptions } from '../../util/navigator_gpu.js'; +import { assert } from '../../util/util.js'; + +import { CTSOptions } from './options.js'; + +export function wrapTestGroupForWorker(g: TestGroup) { + self.onmessage = async (ev: MessageEvent) => { + const query: string = ev.data.query; + const expectations: TestQueryWithExpectation[] = ev.data.expectations; + const ctsOptions: CTSOptions = ev.data.ctsOptions; + + const { debug, unrollConstEvalLoops, powerPreference, compatibility } = ctsOptions; + globalTestConfig.unrollConstEvalLoops = unrollConstEvalLoops; + globalTestConfig.compatibility = compatibility; + + Logger.globalDebugMode = debug; + const log = new Logger(); + + if (powerPreference || compatibility) { + setDefaultRequestAdapterOptions({ + ...(powerPreference && { powerPreference }), + // MAINTENANCE_TODO: Change this to whatever the option ends up being + ...(compatibility && { compatibilityMode: true }), + }); + } + + const testQuery = parseQuery(query); + assert(testQuery instanceof TestQuerySingleCase); + let testcase = null; + for (const t of g.iterate()) { + if (comparePaths(t.testPath, testQuery.testPathParts) !== Ordering.Equal) { + continue; + } + for (const c of t.iterate(testQuery.params)) { + if (comparePublicParamsPaths(c.id.params, testQuery.params) === Ordering.Equal) { + testcase = c; + } + } + } + assert(!!testcase); + const [rec, result] = log.record(query); + await testcase.run(rec, testQuery, expectations); + ev.source?.postMessage({ query, result }); + }; +} diff --git a/src/common/tools/gen_listings_and_webworkers.ts b/src/common/tools/gen_listings_and_webworkers.ts index b922cb763fb8..267273d63747 100644 --- a/src/common/tools/gen_listings_and_webworkers.ts +++ b/src/common/tools/gen_listings_and_webworkers.ts @@ -80,60 +80,9 @@ export const listing = ${JSON.stringify(listing, undefined, 2)}; // g is a TestGroup object (defined in common/internal/test_group.ts). import { g } from '${relPathToSuiteRoot}/${entry.file.join('/')}.spec.js'; +import { wrapTestGroupForWorker } from '${relPathToSuiteRoot}/../common/runtime/helper/wrap_for_worker.js'; -import { globalTestConfig } from '/out/common/framework/test_config.js'; -import { Logger } from '/out/common/internal/logging/logger.js'; -import { setDefaultRequestAdapterOptions } from '/out/common/util/navigator_gpu.js'; -import { parseQuery } from '/out/common/internal/query/parseQuery.js'; -import { comparePublicParamsPaths, Ordering } from '/out/common/internal/query/compare.js'; -import { assert } from '/out/common/util/util.js'; - -async function reportTestResults(ev) { - const query = ev.data.query; - const expectations = ev.data.expectations; - const ctsOptions = ev.data.ctsOptions; - - const { debug, unrollConstEvalLoops, powerPreference, compatibility } = ctsOptions; - globalTestConfig.unrollConstEvalLoops = unrollConstEvalLoops; - globalTestConfig.compatibility = compatibility; - - Logger.globalDebugMode = debug; - const log = new Logger(); - - if (powerPreference || compatibility) { - setDefaultRequestAdapterOptions({ - ...(powerPreference && { powerPreference }), - // MAINTENANCE_TODO: Change this to whatever the option ends up being - ...(compatibility && { compatibilityMode: true }), - }); - } - - const testQuerySingleCase = parseQuery(query); - let testcase = null; - for (const t of g.iterate()) { - for (const c of t.iterate(testQuerySingleCase.params)) { - if (comparePublicParamsPaths(c.id.params, testQuerySingleCase.params) === Ordering.Equal) { - testcase = c; - } - } - } - assert(testcase); - const [rec, result] = log.record(query); - await testcase.run(rec, testQuerySingleCase, expectations); - this.postMessage({ query, result }); -} - -self.onmessage = (ev) => { - void reportTestResults.call(ev.source || self, ev); -}; - -self.onconnect = (event) => { - const port = event.ports[0]; - - port.onmessage = (ev) => { - void reportTestResults.call(port, ev); - }; -}; +wrapTestGroupForWorker(g); ` ); } diff --git a/src/resources/cache/hashes.json b/src/resources/cache/hashes.json index 5a5316cda1f6..1da71bd636e0 100644 --- a/src/resources/cache/hashes.json +++ b/src/resources/cache/hashes.json @@ -1,107 +1,107 @@ { - "webgpu/shader/execution/binary/af_addition.bin": "fc43d206", - "webgpu/shader/execution/binary/af_logical.bin": "3dc912ac", - "webgpu/shader/execution/binary/af_division.bin": "6cbdaf09", - "webgpu/shader/execution/binary/af_matrix_addition.bin": "d61fe049", - "webgpu/shader/execution/binary/af_matrix_subtraction.bin": "16d18276", - "webgpu/shader/execution/binary/af_multiplication.bin": "ce2a0e9e", - "webgpu/shader/execution/binary/af_remainder.bin": "4032e3cf", - "webgpu/shader/execution/binary/af_subtraction.bin": "67a1c189", - "webgpu/shader/execution/binary/f16_addition.bin": "3edd84a3", - "webgpu/shader/execution/binary/f16_logical.bin": "adcc36e9", - "webgpu/shader/execution/binary/f16_division.bin": "81168258", - "webgpu/shader/execution/binary/f16_matrix_addition.bin": "3497729d", - "webgpu/shader/execution/binary/f16_matrix_matrix_multiplication.bin": "767e22c7", - "webgpu/shader/execution/binary/f16_matrix_scalar_multiplication.bin": "356acec0", - "webgpu/shader/execution/binary/f16_matrix_subtraction.bin": "ed00c0e4", - "webgpu/shader/execution/binary/f16_matrix_vector_multiplication.bin": "f089b873", - "webgpu/shader/execution/binary/f16_multiplication.bin": "4675c758", - "webgpu/shader/execution/binary/f16_remainder.bin": "5ea2af46", - "webgpu/shader/execution/binary/f16_subtraction.bin": "a7962472", - "webgpu/shader/execution/binary/f32_addition.bin": "ef624c29", - "webgpu/shader/execution/binary/f32_logical.bin": "68c1e846", - "webgpu/shader/execution/binary/f32_division.bin": "cc886305", - "webgpu/shader/execution/binary/f32_matrix_addition.bin": "b3bab14a", - "webgpu/shader/execution/binary/f32_matrix_matrix_multiplication.bin": "afccd9d5", - "webgpu/shader/execution/binary/f32_matrix_scalar_multiplication.bin": "c8a022a1", - "webgpu/shader/execution/binary/f32_matrix_subtraction.bin": "b0db93fb", - "webgpu/shader/execution/binary/f32_matrix_vector_multiplication.bin": "d90fbe21", - "webgpu/shader/execution/binary/f32_multiplication.bin": "693597cf", - "webgpu/shader/execution/binary/f32_remainder.bin": "fe630a4b", - "webgpu/shader/execution/binary/f32_subtraction.bin": "e3409ba2", - "webgpu/shader/execution/binary/i32_arithmetic.bin": "bd8d0b9b", - "webgpu/shader/execution/binary/i32_comparison.bin": "aec6e622", - "webgpu/shader/execution/binary/u32_arithmetic.bin": "f5907c7e", - "webgpu/shader/execution/binary/u32_comparison.bin": "7160f1c7", - "webgpu/shader/execution/abs.bin": "c884966", - "webgpu/shader/execution/acos.bin": "3e371b22", - "webgpu/shader/execution/acosh.bin": "25b25012", - "webgpu/shader/execution/asin.bin": "75d5b677", - "webgpu/shader/execution/asinh.bin": "92fe4ad3", - "webgpu/shader/execution/atan.bin": "5a7834a4", - "webgpu/shader/execution/atan2.bin": "79487bb", - "webgpu/shader/execution/atanh.bin": "804ad33f", - "webgpu/shader/execution/bitcast.bin": "69a86c70", - "webgpu/shader/execution/ceil.bin": "46bca9a0", - "webgpu/shader/execution/clamp.bin": "620739ae", - "webgpu/shader/execution/cos.bin": "bd7467e4", - "webgpu/shader/execution/cosh.bin": "315aad98", - "webgpu/shader/execution/cross.bin": "d9a91811", - "webgpu/shader/execution/degrees.bin": "27df6eb0", - "webgpu/shader/execution/determinant.bin": "67380eba", - "webgpu/shader/execution/distance.bin": "91d94128", - "webgpu/shader/execution/dot.bin": "3644a88a", - "webgpu/shader/execution/exp.bin": "786e68bc", - "webgpu/shader/execution/exp2.bin": "454ee68d", - "webgpu/shader/execution/faceForward.bin": "625903d3", - "webgpu/shader/execution/floor.bin": "db4c92f7", - "webgpu/shader/execution/fma.bin": "b049ac43", - "webgpu/shader/execution/fract.bin": "84ce9ec3", - "webgpu/shader/execution/frexp.bin": "5320c481", - "webgpu/shader/execution/inverseSqrt.bin": "7aeff2c0", - "webgpu/shader/execution/ldexp.bin": "71b3930f", - "webgpu/shader/execution/length.bin": "e96b503a", - "webgpu/shader/execution/log.bin": "eba7ec7d", - "webgpu/shader/execution/log2.bin": "54ddf967", - "webgpu/shader/execution/max.bin": "a83a582a", - "webgpu/shader/execution/min.bin": "7c2811c1", - "webgpu/shader/execution/mix.bin": "9aa0305f", - "webgpu/shader/execution/modf.bin": "ca3173c2", - "webgpu/shader/execution/normalize.bin": "3c3a347f", - "webgpu/shader/execution/pack2x16float.bin": "73ddf92f", - "webgpu/shader/execution/pow.bin": "d2c3fd97", - "webgpu/shader/execution/quantizeToF16.bin": "ad3587f0", - "webgpu/shader/execution/radians.bin": "d5f10c52", - "webgpu/shader/execution/reflect.bin": "219e2df", - "webgpu/shader/execution/refract.bin": "fa841745", - "webgpu/shader/execution/round.bin": "74f863ec", - "webgpu/shader/execution/saturate.bin": "457fd49d", - "webgpu/shader/execution/sign.bin": "e44d954c", - "webgpu/shader/execution/sin.bin": "67bac1fd", - "webgpu/shader/execution/sinh.bin": "e37cb02b", - "webgpu/shader/execution/smoothstep.bin": "d279bc42", - "webgpu/shader/execution/sqrt.bin": "551939af", - "webgpu/shader/execution/step.bin": "72cf60af", - "webgpu/shader/execution/tan.bin": "f632f032", - "webgpu/shader/execution/tanh.bin": "72c375cb", - "webgpu/shader/execution/transpose.bin": "e968d355", - "webgpu/shader/execution/trunc.bin": "16f79aa5", - "webgpu/shader/execution/unpack2x16float.bin": "c85da768", - "webgpu/shader/execution/unpack2x16snorm.bin": "3f3dbc81", - "webgpu/shader/execution/unpack2x16unorm.bin": "2862cb20", - "webgpu/shader/execution/unpack4x8snorm.bin": "b4c90280", - "webgpu/shader/execution/unpack4x8unorm.bin": "ab1a627b", - "webgpu/shader/execution/unary/af_arithmetic.bin": "67d2b7eb", - "webgpu/shader/execution/unary/af_assignment.bin": "7964e983", - "webgpu/shader/execution/unary/bool_conversion.bin": "349303eb", - "webgpu/shader/execution/unary/f16_arithmetic.bin": "95908291", - "webgpu/shader/execution/unary/f16_conversion.bin": "df34e3f9", - "webgpu/shader/execution/unary/f32_arithmetic.bin": "dea317cd", - "webgpu/shader/execution/unary/f32_conversion.bin": "fb0ff55a", - "webgpu/shader/execution/unary/i32_arithmetic.bin": "d1b09384", - "webgpu/shader/execution/unary/i32_conversion.bin": "7ae3fc76", - "webgpu/shader/execution/unary/u32_conversion.bin": "a1c35c09", - "webgpu/shader/execution/unary/ai_assignment.bin": "bde2f00d", - "webgpu/shader/execution/binary/ai_arithmetic.bin": "f99fb5b7", - "webgpu/shader/execution/unary/ai_arithmetic.bin": "5784ac67" + "webgpu/shader/execution/binary/af_addition.bin": "26c839f3", + "webgpu/shader/execution/binary/af_logical.bin": "8cb7baa9", + "webgpu/shader/execution/binary/af_division.bin": "5bfa337d", + "webgpu/shader/execution/binary/af_matrix_addition.bin": "15e2cc6c", + "webgpu/shader/execution/binary/af_matrix_subtraction.bin": "c4053c51", + "webgpu/shader/execution/binary/af_multiplication.bin": "56dcbeb", + "webgpu/shader/execution/binary/af_remainder.bin": "2a54afb8", + "webgpu/shader/execution/binary/af_subtraction.bin": "747e33d", + "webgpu/shader/execution/binary/f16_addition.bin": "d436308a", + "webgpu/shader/execution/binary/f16_logical.bin": "c5c10109", + "webgpu/shader/execution/binary/f16_division.bin": "f3415323", + "webgpu/shader/execution/binary/f16_matrix_addition.bin": "a7048e1e", + "webgpu/shader/execution/binary/f16_matrix_matrix_multiplication.bin": "e61dd111", + "webgpu/shader/execution/binary/f16_matrix_scalar_multiplication.bin": "b15ead1a", + "webgpu/shader/execution/binary/f16_matrix_subtraction.bin": "eb73c16b", + "webgpu/shader/execution/binary/f16_matrix_vector_multiplication.bin": "87122cb2", + "webgpu/shader/execution/binary/f16_multiplication.bin": "3e1cfdd", + "webgpu/shader/execution/binary/f16_remainder.bin": "22772021", + "webgpu/shader/execution/binary/f16_subtraction.bin": "ef25c2b3", + "webgpu/shader/execution/binary/f32_addition.bin": "a8c1fead", + "webgpu/shader/execution/binary/f32_logical.bin": "61cb3658", + "webgpu/shader/execution/binary/f32_division.bin": "3611d929", + "webgpu/shader/execution/binary/f32_matrix_addition.bin": "c4e0ba95", + "webgpu/shader/execution/binary/f32_matrix_matrix_multiplication.bin": "b955da3b", + "webgpu/shader/execution/binary/f32_matrix_scalar_multiplication.bin": "88771f84", + "webgpu/shader/execution/binary/f32_matrix_subtraction.bin": "9a4c11b5", + "webgpu/shader/execution/binary/f32_matrix_vector_multiplication.bin": "68855926", + "webgpu/shader/execution/binary/f32_multiplication.bin": "71a27ae2", + "webgpu/shader/execution/binary/f32_remainder.bin": "d969b12a", + "webgpu/shader/execution/binary/f32_subtraction.bin": "8f224610", + "webgpu/shader/execution/binary/i32_arithmetic.bin": "30ad7a5a", + "webgpu/shader/execution/binary/i32_comparison.bin": "77147f47", + "webgpu/shader/execution/binary/u32_arithmetic.bin": "ec2909af", + "webgpu/shader/execution/binary/u32_comparison.bin": "522ceb7a", + "webgpu/shader/execution/abs.bin": "8c2cd451", + "webgpu/shader/execution/acos.bin": "51d44bce", + "webgpu/shader/execution/acosh.bin": "42108617", + "webgpu/shader/execution/asin.bin": "8cdfa135", + "webgpu/shader/execution/asinh.bin": "c4098f08", + "webgpu/shader/execution/atan.bin": "d2c4c6f4", + "webgpu/shader/execution/atan2.bin": "458d806", + "webgpu/shader/execution/atanh.bin": "1f3046d7", + "webgpu/shader/execution/bitcast.bin": "bc4ef138", + "webgpu/shader/execution/ceil.bin": "d63bfa45", + "webgpu/shader/execution/clamp.bin": "a72cc7a0", + "webgpu/shader/execution/cos.bin": "4b942fe6", + "webgpu/shader/execution/cosh.bin": "3f4e8659", + "webgpu/shader/execution/cross.bin": "5896e7d4", + "webgpu/shader/execution/degrees.bin": "ddf99143", + "webgpu/shader/execution/determinant.bin": "6541e6e", + "webgpu/shader/execution/distance.bin": "9c5f12ff", + "webgpu/shader/execution/dot.bin": "20287700", + "webgpu/shader/execution/exp.bin": "f2fdb481", + "webgpu/shader/execution/exp2.bin": "98e68bd", + "webgpu/shader/execution/faceForward.bin": "628bb202", + "webgpu/shader/execution/floor.bin": "a90e2bd9", + "webgpu/shader/execution/fma.bin": "197dba2b", + "webgpu/shader/execution/fract.bin": "d06f909b", + "webgpu/shader/execution/frexp.bin": "f9892b7b", + "webgpu/shader/execution/inverseSqrt.bin": "126eeeca", + "webgpu/shader/execution/ldexp.bin": "5b190eb8", + "webgpu/shader/execution/length.bin": "4928fb2", + "webgpu/shader/execution/log.bin": "1041194c", + "webgpu/shader/execution/log2.bin": "e34a4602", + "webgpu/shader/execution/max.bin": "a9f2264c", + "webgpu/shader/execution/min.bin": "f73df563", + "webgpu/shader/execution/mix.bin": "63c7abe1", + "webgpu/shader/execution/modf.bin": "72a62d62", + "webgpu/shader/execution/normalize.bin": "123fbc90", + "webgpu/shader/execution/pack2x16float.bin": "87b76e98", + "webgpu/shader/execution/pow.bin": "8434384c", + "webgpu/shader/execution/quantizeToF16.bin": "46f03192", + "webgpu/shader/execution/radians.bin": "b951d73", + "webgpu/shader/execution/reflect.bin": "23d10a66", + "webgpu/shader/execution/refract.bin": "34a865b3", + "webgpu/shader/execution/round.bin": "1e011783", + "webgpu/shader/execution/saturate.bin": "17607b79", + "webgpu/shader/execution/sign.bin": "9bea75b2", + "webgpu/shader/execution/sin.bin": "874922c6", + "webgpu/shader/execution/sinh.bin": "b634ab6c", + "webgpu/shader/execution/smoothstep.bin": "c75008c", + "webgpu/shader/execution/sqrt.bin": "87847268", + "webgpu/shader/execution/step.bin": "c9776350", + "webgpu/shader/execution/tan.bin": "f11f930b", + "webgpu/shader/execution/tanh.bin": "c86dce7c", + "webgpu/shader/execution/transpose.bin": "3e691d19", + "webgpu/shader/execution/trunc.bin": "b8cedd5e", + "webgpu/shader/execution/unpack2x16float.bin": "164932c2", + "webgpu/shader/execution/unpack2x16snorm.bin": "14430f38", + "webgpu/shader/execution/unpack2x16unorm.bin": "2c798bbc", + "webgpu/shader/execution/unpack4x8snorm.bin": "9fd6301", + "webgpu/shader/execution/unpack4x8unorm.bin": "534c4f7b", + "webgpu/shader/execution/unary/af_arithmetic.bin": "a2a92cc7", + "webgpu/shader/execution/unary/af_assignment.bin": "8b36668", + "webgpu/shader/execution/unary/bool_conversion.bin": "2a937fe2", + "webgpu/shader/execution/unary/f16_arithmetic.bin": "f362e104", + "webgpu/shader/execution/unary/f16_conversion.bin": "a33af291", + "webgpu/shader/execution/unary/f32_arithmetic.bin": "9d4ebd3d", + "webgpu/shader/execution/unary/f32_conversion.bin": "55b007fd", + "webgpu/shader/execution/unary/i32_arithmetic.bin": "188397c0", + "webgpu/shader/execution/unary/i32_conversion.bin": "ffa6aa43", + "webgpu/shader/execution/unary/u32_conversion.bin": "8dffc602", + "webgpu/shader/execution/unary/ai_assignment.bin": "a84b66e", + "webgpu/shader/execution/binary/ai_arithmetic.bin": "77d0d588", + "webgpu/shader/execution/unary/ai_arithmetic.bin": "5b0fe7e" } \ No newline at end of file diff --git a/src/webgpu/web_platform/worker/worker.spec.ts b/src/webgpu/web_platform/worker/worker.spec.ts index 9b93a5d5339e..1527dd2d2f16 100644 --- a/src/webgpu/web_platform/worker/worker.spec.ts +++ b/src/webgpu/web_platform/worker/worker.spec.ts @@ -12,6 +12,12 @@ import { assert } from '../../../common/util/util.js'; export const g = makeTestGroup(Fixture); +// Note: we load worker_launcher dynamically because ts-node support +// is using commonjs which doesn't support import.meta. Further, +// we need to put the url in a string and pass the string to import +// otherwise typescript tries to parse the file which again, fails. +// worker_launcher.js is excluded in node.tsconfig.json. + function isNode(): boolean { return typeof process !== 'undefined' && process?.versions?.node !== undefined; } @@ -19,15 +25,7 @@ function isNode(): boolean { g.test('dedicated_worker') .desc(`test WebGPU is available in dedicated workers and check for basic functionality`) .fn(async t => { - if (isNode()) { - t.skip('node does not support 100% compatible workers'); - return; - } - // Note: we load worker_launcher dynamically because ts-node support - // is using commonjs which doesn't support import.meta. Further, - // we need to put the url in a string add pass the string to import - // otherwise typescript tries to parse the file which again, fails. - // worker_launcher.js is excluded in node.tsconfig.json. + t.skipIf(isNode(), 'node does not support 100% compatible workers'); const url = './worker_launcher.js'; const { launchDedicatedWorker } = await import(url); const result = await launchDedicatedWorker(); @@ -37,15 +35,7 @@ g.test('dedicated_worker') g.test('shared_worker') .desc(`test WebGPU is available in shared workers and check for basic functionality`) .fn(async t => { - if (isNode()) { - t.skip('node does not support 100% compatible workers'); - return; - } - // Note: we load worker_launcher dynamically because ts-node support - // is using commonjs which doesn't support import.meta. Further, - // we need to put the url in a string add pass the string to import - // otherwise typescript tries to parse the file which again, fails. - // worker_launcher.js is excluded in node.tsconfig.json. + t.skipIf(isNode(), 'node does not support 100% compatible workers'); const url = './worker_launcher.js'; const { launchSharedWorker } = await import(url); const result = await launchSharedWorker(); @@ -55,15 +45,7 @@ g.test('shared_worker') g.test('service_worker') .desc(`test WebGPU is available in service workers and check for basic functionality`) .fn(async t => { - if (isNode()) { - t.skip('node does not support 100% compatible workers'); - return; - } - // Note: we load worker_launcher dynamically because ts-node support - // is using commonjs which doesn't support import.meta. Further, - // we need to put the url in a string add pass the string to import - // otherwise typescript tries to parse the file which again, fails. - // worker_launcher.js is excluded in node.tsconfig.json. + t.skipIf(isNode(), 'node does not support 100% compatible workers'); const url = './worker_launcher.js'; const { launchServiceWorker } = await import(url); const result = await launchServiceWorker(); From 5d0e4c035da0d09455e2981158e5fa7e5939d753 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Beaufort?= Date: Wed, 6 Mar 2024 21:17:31 +0100 Subject: [PATCH 06/22] Address feedback | part 2 --- src/common/internal/query/compare.ts | 3 +++ src/common/runtime/helper/test_worker.ts | 1 - src/common/tools/dev_server.ts | 2 -- src/webgpu/web_platform/worker/worker_launcher.ts | 1 - 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/common/internal/query/compare.ts b/src/common/internal/query/compare.ts index 39b263f4deeb..f49833f5a2e0 100644 --- a/src/common/internal/query/compare.ts +++ b/src/common/internal/query/compare.ts @@ -58,6 +58,9 @@ function compareOneLevel(ordering: Ordering, aIsBig: boolean, bIsBig: boolean): return Ordering.Unordered; } +/** + * Compare two file paths, or file-local test paths, returning an Ordering between the two. + */ export function comparePaths(a: readonly string[], b: readonly string[]): Ordering { const shorter = Math.min(a.length, b.length); diff --git a/src/common/runtime/helper/test_worker.ts b/src/common/runtime/helper/test_worker.ts index 174a9170a0dd..63bf6338c90d 100644 --- a/src/common/runtime/helper/test_worker.ts +++ b/src/common/runtime/helper/test_worker.ts @@ -106,7 +106,6 @@ export class TestServiceWorker extends TestBaseWorker { const registration = await navigator.serviceWorker.register(serviceWorkerPath, { type: 'module', - scope: '/', }); await registration.update(); navigator.serviceWorker.onmessage = ev => this.onmessage(ev); diff --git a/src/common/tools/dev_server.ts b/src/common/tools/dev_server.ts index 2845a2375524..ca52fdc93568 100644 --- a/src/common/tools/dev_server.ts +++ b/src/common/tools/dev_server.ts @@ -150,7 +150,6 @@ app.get('/out/**/*.js', async (req, res, next) => { const tsUrl = jsUrl.replace(/\.js$/, '.ts'); if (compileCache.has(tsUrl)) { res.setHeader('Content-Type', 'application/javascript'); - res.setHeader('Service-Worker-Allowed', '/'); res.send(compileCache.get(tsUrl)); return; } @@ -169,7 +168,6 @@ app.get('/out/**/*.js', async (req, res, next) => { compileCache.set(tsUrl, result.code); res.setHeader('Content-Type', 'application/javascript'); - res.setHeader('Service-Worker-Allowed', '/'); res.send(result.code); } else { throw new Error(`Failed compile ${tsUrl}.`); diff --git a/src/webgpu/web_platform/worker/worker_launcher.ts b/src/webgpu/web_platform/worker/worker_launcher.ts index 1fa62ba5b1e0..ab2bf82a1c01 100644 --- a/src/webgpu/web_platform/worker/worker_launcher.ts +++ b/src/webgpu/web_platform/worker/worker_launcher.ts @@ -40,7 +40,6 @@ export async function launchServiceWorker() { const serviceWorkerPath = selfPathDir + '/worker.js'; const registration = await navigator.serviceWorker.register(serviceWorkerPath, { type: 'module', - scope: '/', }); await registration.update(); From 4ea5270c8adc101c5eef13ab541c43e817b91864 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Beaufort?= Date: Wed, 6 Mar 2024 21:33:49 +0100 Subject: [PATCH 07/22] Address feedback | part 3 --- .../runtime/helper/test_worker-worker.ts | 19 +- src/common/runtime/helper/utils_worker.ts | 24 ++ src/common/runtime/helper/wrap_for_worker.ts | 19 +- src/resources/cache/hashes.json | 210 +++++++++--------- 4 files changed, 133 insertions(+), 139 deletions(-) create mode 100644 src/common/runtime/helper/utils_worker.ts diff --git a/src/common/runtime/helper/test_worker-worker.ts b/src/common/runtime/helper/test_worker-worker.ts index 25d9a3d33647..5223d2e8b61e 100644 --- a/src/common/runtime/helper/test_worker-worker.ts +++ b/src/common/runtime/helper/test_worker-worker.ts @@ -1,13 +1,11 @@ import { setBaseResourcePath } from '../../framework/resources.js'; -import { globalTestConfig } from '../../framework/test_config.js'; import { DefaultTestFileLoader } from '../../internal/file_loader.js'; -import { Logger } from '../../internal/logging/logger.js'; import { parseQuery } from '../../internal/query/parseQuery.js'; import { TestQueryWithExpectation } from '../../internal/query/query.js'; -import { setDefaultRequestAdapterOptions } from '../../util/navigator_gpu.js'; import { assert } from '../../util/util.js'; import { CTSOptions } from './options.js'; +import { setupWorkerEnvironment } from './utils_worker.js'; // Should be WorkerGlobalScope, but importing lib "webworker" conflicts with lib "dom". /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ @@ -22,20 +20,7 @@ async function reportTestResults(this: MessagePort | Worker, ev: MessageEvent) { const expectations: TestQueryWithExpectation[] = ev.data.expectations; const ctsOptions: CTSOptions = ev.data.ctsOptions; - const { debug, unrollConstEvalLoops, powerPreference, compatibility } = ctsOptions; - globalTestConfig.unrollConstEvalLoops = unrollConstEvalLoops; - globalTestConfig.compatibility = compatibility; - - Logger.globalDebugMode = debug; - const log = new Logger(); - - if (powerPreference || compatibility) { - setDefaultRequestAdapterOptions({ - ...(powerPreference && { powerPreference }), - // MAINTENANCE_TODO: Change this to whatever the option ends up being - ...(compatibility && { compatibilityMode: true }), - }); - } + const log = setupWorkerEnvironment(ctsOptions); const testcases = Array.from(await loader.loadCases(parseQuery(query))); assert(testcases.length === 1, 'worker query resulted in != 1 cases'); diff --git a/src/common/runtime/helper/utils_worker.ts b/src/common/runtime/helper/utils_worker.ts new file mode 100644 index 000000000000..6dca3f831c38 --- /dev/null +++ b/src/common/runtime/helper/utils_worker.ts @@ -0,0 +1,24 @@ +import { globalTestConfig } from '../../framework/test_config.js'; +import { Logger } from '../../internal/logging/logger.js'; +import { setDefaultRequestAdapterOptions } from '../../util/navigator_gpu.js'; + +import { CTSOptions } from './options.js'; + +export function setupWorkerEnvironment(ctsOptions: CTSOptions): Logger { + const { debug, unrollConstEvalLoops, powerPreference, compatibility } = ctsOptions; + globalTestConfig.unrollConstEvalLoops = unrollConstEvalLoops; + globalTestConfig.compatibility = compatibility; + + Logger.globalDebugMode = debug; + const log = new Logger(); + + if (powerPreference || compatibility) { + setDefaultRequestAdapterOptions({ + ...(powerPreference && { powerPreference }), + // MAINTENANCE_TODO: Change this to whatever the option ends up being + ...(compatibility && { compatibilityMode: true }), + }); + } + + return log; +} diff --git a/src/common/runtime/helper/wrap_for_worker.ts b/src/common/runtime/helper/wrap_for_worker.ts index b804ae6088e5..8124df8ab7a9 100644 --- a/src/common/runtime/helper/wrap_for_worker.ts +++ b/src/common/runtime/helper/wrap_for_worker.ts @@ -1,14 +1,12 @@ import { Fixture } from '../../framework/fixture'; -import { globalTestConfig } from '../../framework/test_config.js'; -import { Logger } from '../../internal/logging/logger.js'; import { comparePaths, comparePublicParamsPaths, Ordering } from '../../internal/query/compare.js'; import { parseQuery } from '../../internal/query/parseQuery.js'; import { TestQuerySingleCase, TestQueryWithExpectation } from '../../internal/query/query.js'; import { TestGroup } from '../../internal/test_group.js'; -import { setDefaultRequestAdapterOptions } from '../../util/navigator_gpu.js'; import { assert } from '../../util/util.js'; import { CTSOptions } from './options.js'; +import { setupWorkerEnvironment } from './utils_worker.js'; export function wrapTestGroupForWorker(g: TestGroup) { self.onmessage = async (ev: MessageEvent) => { @@ -16,20 +14,7 @@ export function wrapTestGroupForWorker(g: TestGroup) { const expectations: TestQueryWithExpectation[] = ev.data.expectations; const ctsOptions: CTSOptions = ev.data.ctsOptions; - const { debug, unrollConstEvalLoops, powerPreference, compatibility } = ctsOptions; - globalTestConfig.unrollConstEvalLoops = unrollConstEvalLoops; - globalTestConfig.compatibility = compatibility; - - Logger.globalDebugMode = debug; - const log = new Logger(); - - if (powerPreference || compatibility) { - setDefaultRequestAdapterOptions({ - ...(powerPreference && { powerPreference }), - // MAINTENANCE_TODO: Change this to whatever the option ends up being - ...(compatibility && { compatibilityMode: true }), - }); - } + const log = setupWorkerEnvironment(ctsOptions); const testQuery = parseQuery(query); assert(testQuery instanceof TestQuerySingleCase); diff --git a/src/resources/cache/hashes.json b/src/resources/cache/hashes.json index 1da71bd636e0..34ba42622b9b 100644 --- a/src/resources/cache/hashes.json +++ b/src/resources/cache/hashes.json @@ -1,107 +1,107 @@ { - "webgpu/shader/execution/binary/af_addition.bin": "26c839f3", - "webgpu/shader/execution/binary/af_logical.bin": "8cb7baa9", - "webgpu/shader/execution/binary/af_division.bin": "5bfa337d", - "webgpu/shader/execution/binary/af_matrix_addition.bin": "15e2cc6c", - "webgpu/shader/execution/binary/af_matrix_subtraction.bin": "c4053c51", - "webgpu/shader/execution/binary/af_multiplication.bin": "56dcbeb", - "webgpu/shader/execution/binary/af_remainder.bin": "2a54afb8", - "webgpu/shader/execution/binary/af_subtraction.bin": "747e33d", - "webgpu/shader/execution/binary/f16_addition.bin": "d436308a", - "webgpu/shader/execution/binary/f16_logical.bin": "c5c10109", - "webgpu/shader/execution/binary/f16_division.bin": "f3415323", - "webgpu/shader/execution/binary/f16_matrix_addition.bin": "a7048e1e", - "webgpu/shader/execution/binary/f16_matrix_matrix_multiplication.bin": "e61dd111", - "webgpu/shader/execution/binary/f16_matrix_scalar_multiplication.bin": "b15ead1a", - "webgpu/shader/execution/binary/f16_matrix_subtraction.bin": "eb73c16b", - "webgpu/shader/execution/binary/f16_matrix_vector_multiplication.bin": "87122cb2", - "webgpu/shader/execution/binary/f16_multiplication.bin": "3e1cfdd", - "webgpu/shader/execution/binary/f16_remainder.bin": "22772021", - "webgpu/shader/execution/binary/f16_subtraction.bin": "ef25c2b3", - "webgpu/shader/execution/binary/f32_addition.bin": "a8c1fead", - "webgpu/shader/execution/binary/f32_logical.bin": "61cb3658", - "webgpu/shader/execution/binary/f32_division.bin": "3611d929", - "webgpu/shader/execution/binary/f32_matrix_addition.bin": "c4e0ba95", - "webgpu/shader/execution/binary/f32_matrix_matrix_multiplication.bin": "b955da3b", - "webgpu/shader/execution/binary/f32_matrix_scalar_multiplication.bin": "88771f84", - "webgpu/shader/execution/binary/f32_matrix_subtraction.bin": "9a4c11b5", - "webgpu/shader/execution/binary/f32_matrix_vector_multiplication.bin": "68855926", - "webgpu/shader/execution/binary/f32_multiplication.bin": "71a27ae2", - "webgpu/shader/execution/binary/f32_remainder.bin": "d969b12a", - "webgpu/shader/execution/binary/f32_subtraction.bin": "8f224610", - "webgpu/shader/execution/binary/i32_arithmetic.bin": "30ad7a5a", - "webgpu/shader/execution/binary/i32_comparison.bin": "77147f47", - "webgpu/shader/execution/binary/u32_arithmetic.bin": "ec2909af", - "webgpu/shader/execution/binary/u32_comparison.bin": "522ceb7a", - "webgpu/shader/execution/abs.bin": "8c2cd451", - "webgpu/shader/execution/acos.bin": "51d44bce", - "webgpu/shader/execution/acosh.bin": "42108617", - "webgpu/shader/execution/asin.bin": "8cdfa135", - "webgpu/shader/execution/asinh.bin": "c4098f08", - "webgpu/shader/execution/atan.bin": "d2c4c6f4", - "webgpu/shader/execution/atan2.bin": "458d806", - "webgpu/shader/execution/atanh.bin": "1f3046d7", - "webgpu/shader/execution/bitcast.bin": "bc4ef138", - "webgpu/shader/execution/ceil.bin": "d63bfa45", - "webgpu/shader/execution/clamp.bin": "a72cc7a0", - "webgpu/shader/execution/cos.bin": "4b942fe6", - "webgpu/shader/execution/cosh.bin": "3f4e8659", - "webgpu/shader/execution/cross.bin": "5896e7d4", - "webgpu/shader/execution/degrees.bin": "ddf99143", - "webgpu/shader/execution/determinant.bin": "6541e6e", - "webgpu/shader/execution/distance.bin": "9c5f12ff", - "webgpu/shader/execution/dot.bin": "20287700", - "webgpu/shader/execution/exp.bin": "f2fdb481", - "webgpu/shader/execution/exp2.bin": "98e68bd", - "webgpu/shader/execution/faceForward.bin": "628bb202", - "webgpu/shader/execution/floor.bin": "a90e2bd9", - "webgpu/shader/execution/fma.bin": "197dba2b", - "webgpu/shader/execution/fract.bin": "d06f909b", - "webgpu/shader/execution/frexp.bin": "f9892b7b", - "webgpu/shader/execution/inverseSqrt.bin": "126eeeca", - "webgpu/shader/execution/ldexp.bin": "5b190eb8", - "webgpu/shader/execution/length.bin": "4928fb2", - "webgpu/shader/execution/log.bin": "1041194c", - "webgpu/shader/execution/log2.bin": "e34a4602", - "webgpu/shader/execution/max.bin": "a9f2264c", - "webgpu/shader/execution/min.bin": "f73df563", - "webgpu/shader/execution/mix.bin": "63c7abe1", - "webgpu/shader/execution/modf.bin": "72a62d62", - "webgpu/shader/execution/normalize.bin": "123fbc90", - "webgpu/shader/execution/pack2x16float.bin": "87b76e98", - "webgpu/shader/execution/pow.bin": "8434384c", - "webgpu/shader/execution/quantizeToF16.bin": "46f03192", - "webgpu/shader/execution/radians.bin": "b951d73", - "webgpu/shader/execution/reflect.bin": "23d10a66", - "webgpu/shader/execution/refract.bin": "34a865b3", - "webgpu/shader/execution/round.bin": "1e011783", - "webgpu/shader/execution/saturate.bin": "17607b79", - "webgpu/shader/execution/sign.bin": "9bea75b2", - "webgpu/shader/execution/sin.bin": "874922c6", - "webgpu/shader/execution/sinh.bin": "b634ab6c", - "webgpu/shader/execution/smoothstep.bin": "c75008c", - "webgpu/shader/execution/sqrt.bin": "87847268", - "webgpu/shader/execution/step.bin": "c9776350", - "webgpu/shader/execution/tan.bin": "f11f930b", - "webgpu/shader/execution/tanh.bin": "c86dce7c", - "webgpu/shader/execution/transpose.bin": "3e691d19", - "webgpu/shader/execution/trunc.bin": "b8cedd5e", - "webgpu/shader/execution/unpack2x16float.bin": "164932c2", - "webgpu/shader/execution/unpack2x16snorm.bin": "14430f38", - "webgpu/shader/execution/unpack2x16unorm.bin": "2c798bbc", - "webgpu/shader/execution/unpack4x8snorm.bin": "9fd6301", - "webgpu/shader/execution/unpack4x8unorm.bin": "534c4f7b", - "webgpu/shader/execution/unary/af_arithmetic.bin": "a2a92cc7", - "webgpu/shader/execution/unary/af_assignment.bin": "8b36668", - "webgpu/shader/execution/unary/bool_conversion.bin": "2a937fe2", - "webgpu/shader/execution/unary/f16_arithmetic.bin": "f362e104", - "webgpu/shader/execution/unary/f16_conversion.bin": "a33af291", - "webgpu/shader/execution/unary/f32_arithmetic.bin": "9d4ebd3d", - "webgpu/shader/execution/unary/f32_conversion.bin": "55b007fd", - "webgpu/shader/execution/unary/i32_arithmetic.bin": "188397c0", - "webgpu/shader/execution/unary/i32_conversion.bin": "ffa6aa43", - "webgpu/shader/execution/unary/u32_conversion.bin": "8dffc602", - "webgpu/shader/execution/unary/ai_assignment.bin": "a84b66e", - "webgpu/shader/execution/binary/ai_arithmetic.bin": "77d0d588", - "webgpu/shader/execution/unary/ai_arithmetic.bin": "5b0fe7e" + "webgpu/shader/execution/binary/af_addition.bin": "4d0536fb", + "webgpu/shader/execution/binary/af_logical.bin": "92be6c3a", + "webgpu/shader/execution/binary/af_division.bin": "13619588", + "webgpu/shader/execution/binary/af_matrix_addition.bin": "fd519b9f", + "webgpu/shader/execution/binary/af_matrix_subtraction.bin": "cf2c50c2", + "webgpu/shader/execution/binary/af_multiplication.bin": "f341ec79", + "webgpu/shader/execution/binary/af_remainder.bin": "855f749c", + "webgpu/shader/execution/binary/af_subtraction.bin": "5609592b", + "webgpu/shader/execution/binary/f16_addition.bin": "c3d581cc", + "webgpu/shader/execution/binary/f16_logical.bin": "3a206ca5", + "webgpu/shader/execution/binary/f16_division.bin": "30a47c5b", + "webgpu/shader/execution/binary/f16_matrix_addition.bin": "e7d0fcde", + "webgpu/shader/execution/binary/f16_matrix_matrix_multiplication.bin": "a6794c30", + "webgpu/shader/execution/binary/f16_matrix_scalar_multiplication.bin": "74fe9110", + "webgpu/shader/execution/binary/f16_matrix_subtraction.bin": "a7e2c458", + "webgpu/shader/execution/binary/f16_matrix_vector_multiplication.bin": "c36cfa91", + "webgpu/shader/execution/binary/f16_multiplication.bin": "ce25eb21", + "webgpu/shader/execution/binary/f16_remainder.bin": "1929ee03", + "webgpu/shader/execution/binary/f16_subtraction.bin": "abefb7f6", + "webgpu/shader/execution/binary/f32_addition.bin": "7cf82719", + "webgpu/shader/execution/binary/f32_logical.bin": "239c8ffd", + "webgpu/shader/execution/binary/f32_division.bin": "ab9bb081", + "webgpu/shader/execution/binary/f32_matrix_addition.bin": "c8339d54", + "webgpu/shader/execution/binary/f32_matrix_matrix_multiplication.bin": "67e2f016", + "webgpu/shader/execution/binary/f32_matrix_scalar_multiplication.bin": "411135b5", + "webgpu/shader/execution/binary/f32_matrix_subtraction.bin": "87d5e4fd", + "webgpu/shader/execution/binary/f32_matrix_vector_multiplication.bin": "ec916728", + "webgpu/shader/execution/binary/f32_multiplication.bin": "18514af6", + "webgpu/shader/execution/binary/f32_remainder.bin": "e0cba30e", + "webgpu/shader/execution/binary/f32_subtraction.bin": "d9f0bcdd", + "webgpu/shader/execution/binary/i32_arithmetic.bin": "d855e86c", + "webgpu/shader/execution/binary/i32_comparison.bin": "fb72c69e", + "webgpu/shader/execution/binary/u32_arithmetic.bin": "e6de170a", + "webgpu/shader/execution/binary/u32_comparison.bin": "94440308", + "webgpu/shader/execution/abs.bin": "20f7ba30", + "webgpu/shader/execution/acos.bin": "b4aa499b", + "webgpu/shader/execution/acosh.bin": "dfc3b60b", + "webgpu/shader/execution/asin.bin": "8d100941", + "webgpu/shader/execution/asinh.bin": "21ef328e", + "webgpu/shader/execution/atan.bin": "956e7a7d", + "webgpu/shader/execution/atan2.bin": "d2175546", + "webgpu/shader/execution/atanh.bin": "d047d169", + "webgpu/shader/execution/bitcast.bin": "336d0620", + "webgpu/shader/execution/ceil.bin": "949e3a6c", + "webgpu/shader/execution/clamp.bin": "7afefc1b", + "webgpu/shader/execution/cos.bin": "2b62bc14", + "webgpu/shader/execution/cosh.bin": "eba57bcf", + "webgpu/shader/execution/cross.bin": "6f9cc57c", + "webgpu/shader/execution/degrees.bin": "b6363b42", + "webgpu/shader/execution/determinant.bin": "f8ca5e18", + "webgpu/shader/execution/distance.bin": "a6c0fdd3", + "webgpu/shader/execution/dot.bin": "db8f1011", + "webgpu/shader/execution/exp.bin": "824d312b", + "webgpu/shader/execution/exp2.bin": "51c0492f", + "webgpu/shader/execution/faceForward.bin": "d3366785", + "webgpu/shader/execution/floor.bin": "1f2db342", + "webgpu/shader/execution/fma.bin": "ecec8658", + "webgpu/shader/execution/fract.bin": "d0b8fdca", + "webgpu/shader/execution/frexp.bin": "504a2db4", + "webgpu/shader/execution/inverseSqrt.bin": "9ddcaac3", + "webgpu/shader/execution/ldexp.bin": "c1fff1c8", + "webgpu/shader/execution/length.bin": "439dd339", + "webgpu/shader/execution/log.bin": "14481e5c", + "webgpu/shader/execution/log2.bin": "8001df0c", + "webgpu/shader/execution/max.bin": "9cd00770", + "webgpu/shader/execution/min.bin": "b7feec8c", + "webgpu/shader/execution/mix.bin": "e6e6e999", + "webgpu/shader/execution/modf.bin": "d3201375", + "webgpu/shader/execution/normalize.bin": "9eb7856d", + "webgpu/shader/execution/pack2x16float.bin": "f33b1ac4", + "webgpu/shader/execution/pow.bin": "3d46ef8d", + "webgpu/shader/execution/quantizeToF16.bin": "5e70cb76", + "webgpu/shader/execution/radians.bin": "2cc0617e", + "webgpu/shader/execution/reflect.bin": "1cf2822d", + "webgpu/shader/execution/refract.bin": "db14bf5c", + "webgpu/shader/execution/round.bin": "b88961ad", + "webgpu/shader/execution/saturate.bin": "1e895d9d", + "webgpu/shader/execution/sign.bin": "fbd09407", + "webgpu/shader/execution/sin.bin": "f7c15f5", + "webgpu/shader/execution/sinh.bin": "d5fff9e1", + "webgpu/shader/execution/smoothstep.bin": "1e089581", + "webgpu/shader/execution/sqrt.bin": "29c5f7a2", + "webgpu/shader/execution/step.bin": "b9acbeab", + "webgpu/shader/execution/tan.bin": "9efc9edc", + "webgpu/shader/execution/tanh.bin": "6718fde", + "webgpu/shader/execution/transpose.bin": "7da8cdb8", + "webgpu/shader/execution/trunc.bin": "b4cfa33a", + "webgpu/shader/execution/unpack2x16float.bin": "1287543e", + "webgpu/shader/execution/unpack2x16snorm.bin": "968d300f", + "webgpu/shader/execution/unpack2x16unorm.bin": "c0cfb858", + "webgpu/shader/execution/unpack4x8snorm.bin": "874bb534", + "webgpu/shader/execution/unpack4x8unorm.bin": "1f57b96", + "webgpu/shader/execution/unary/af_arithmetic.bin": "1646d68d", + "webgpu/shader/execution/unary/af_assignment.bin": "8c27e2c5", + "webgpu/shader/execution/unary/bool_conversion.bin": "38daa612", + "webgpu/shader/execution/unary/f16_arithmetic.bin": "9a0ce6e6", + "webgpu/shader/execution/unary/f16_conversion.bin": "22ba9647", + "webgpu/shader/execution/unary/f32_arithmetic.bin": "e2263439", + "webgpu/shader/execution/unary/f32_conversion.bin": "3853c07c", + "webgpu/shader/execution/unary/i32_arithmetic.bin": "8b59d3c0", + "webgpu/shader/execution/unary/i32_conversion.bin": "bccbd92a", + "webgpu/shader/execution/unary/u32_conversion.bin": "f74c82ed", + "webgpu/shader/execution/unary/ai_assignment.bin": "251daef8", + "webgpu/shader/execution/binary/ai_arithmetic.bin": "94c9d04b", + "webgpu/shader/execution/unary/ai_arithmetic.bin": "963b5f83" } \ No newline at end of file From 46683bf6888c06d1c7a7f8033e4fa45b14d48732 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Beaufort?= Date: Thu, 7 Mar 2024 10:12:27 +0100 Subject: [PATCH 08/22] Address feedback | part 4 --- src/common/runtime/helper/test_worker.ts | 60 ++++++++++++----------- src/common/runtime/helper/utils_worker.ts | 3 ++ 2 files changed, 34 insertions(+), 29 deletions(-) diff --git a/src/common/runtime/helper/test_worker.ts b/src/common/runtime/helper/test_worker.ts index 63bf6338c90d..7a016275813c 100644 --- a/src/common/runtime/helper/test_worker.ts +++ b/src/common/runtime/helper/test_worker.ts @@ -2,9 +2,16 @@ import { LogMessageWithStack } from '../../internal/logging/log_message.js'; import { TransferredTestCaseResult, LiveTestCaseResult } from '../../internal/logging/result.js'; import { TestCaseRecorder } from '../../internal/logging/test_case_recorder.js'; import { TestQueryWithExpectation } from '../../internal/query/query.js'; +import { assert } from '../../util/util.js'; import { CTSOptions, kDefaultCTSOptions } from './options.js'; +interface WorkerTestRunRequest { + rec: TestCaseRecorder; + query: string; + expectations: TestQueryWithExpectation[]; +} + class TestBaseWorker { protected readonly ctsOptions: CTSOptions; protected readonly resolvers = new Map void>(); @@ -26,6 +33,22 @@ class TestBaseWorker { // MAINTENANCE_TODO(kainino0x): update the Logger with this result (or don't have a logger and // update the entire results JSON somehow at some point). } + + async makeRequestAndRecordResult( + target: MessagePort | Worker | ServiceWorker, + request: WorkerTestRunRequest + ) { + const { query, expectations, rec } = request; + target.postMessage({ + query, + expectations, + ctsOptions: this.ctsOptions, + }); + const workerResult = await new Promise(resolve => { + this.resolvers.set(query, resolve); + }); + rec.injectResult(workerResult); + } } export class TestDedicatedWorker extends TestBaseWorker { @@ -45,15 +68,8 @@ export class TestDedicatedWorker extends TestBaseWorker { query: string, expectations: TestQueryWithExpectation[] = [] ): Promise { - this.worker.postMessage({ - query, - expectations, - ctsOptions: this.ctsOptions, - }); - const workerResult = await new Promise(resolve => { - this.resolvers.set(query, resolve); - }); - rec.injectResult(workerResult); + const request: WorkerTestRunRequest = { rec, query, expectations }; + await this.makeRequestAndRecordResult(this.worker, request); } } @@ -78,15 +94,8 @@ export class TestSharedWorker extends TestBaseWorker { query: string, expectations: TestQueryWithExpectation[] = [] ): Promise { - this.port.postMessage({ - query, - expectations, - ctsOptions: this.ctsOptions, - }); - const workerResult = await new Promise(resolve => { - this.resolvers.set(query, resolve); - }); - rec.injectResult(workerResult); + const request: WorkerTestRunRequest = { rec, query, expectations }; + await this.makeRequestAndRecordResult(this.port, request); } } @@ -109,16 +118,9 @@ export class TestServiceWorker extends TestBaseWorker { }); await registration.update(); navigator.serviceWorker.onmessage = ev => this.onmessage(ev); - - registration.active?.postMessage({ - query, - expectations, - ctsOptions: this.ctsOptions, - }); - const serviceWorkerResult = await new Promise(resolve => { - this.resolvers.set(query, resolve); - void registration.unregister(); - }); - rec.injectResult(serviceWorkerResult); + assert(!!registration.active); + const request: WorkerTestRunRequest = { rec, query, expectations }; + await this.makeRequestAndRecordResult(registration.active, request); + void registration.unregister(); } } diff --git a/src/common/runtime/helper/utils_worker.ts b/src/common/runtime/helper/utils_worker.ts index 6dca3f831c38..b4d09f8ac2c2 100644 --- a/src/common/runtime/helper/utils_worker.ts +++ b/src/common/runtime/helper/utils_worker.ts @@ -4,6 +4,9 @@ import { setDefaultRequestAdapterOptions } from '../../util/navigator_gpu.js'; import { CTSOptions } from './options.js'; +/* + * Set config environement for workers based on CTSOptions and return a Logger. + */ export function setupWorkerEnvironment(ctsOptions: CTSOptions): Logger { const { debug, unrollConstEvalLoops, powerPreference, compatibility } = ctsOptions; globalTestConfig.unrollConstEvalLoops = unrollConstEvalLoops; From b5b8538161277f09900b599d140d80706530ef46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Beaufort?= Date: Thu, 7 Mar 2024 10:17:28 +0100 Subject: [PATCH 09/22] Address feedback | part 5 --- src/common/runtime/helper/utils_worker.ts | 2 +- src/common/tools/gen_listings_and_webworkers.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/runtime/helper/utils_worker.ts b/src/common/runtime/helper/utils_worker.ts index b4d09f8ac2c2..7be4d10a57fc 100644 --- a/src/common/runtime/helper/utils_worker.ts +++ b/src/common/runtime/helper/utils_worker.ts @@ -5,7 +5,7 @@ import { setDefaultRequestAdapterOptions } from '../../util/navigator_gpu.js'; import { CTSOptions } from './options.js'; /* - * Set config environement for workers based on CTSOptions and return a Logger. + * Set config environment for workers with ctsOptions and return a Logger. */ export function setupWorkerEnvironment(ctsOptions: CTSOptions): Logger { const { debug, unrollConstEvalLoops, powerPreference, compatibility } = ctsOptions; diff --git a/src/common/tools/gen_listings_and_webworkers.ts b/src/common/tools/gen_listings_and_webworkers.ts index 267273d63747..d9df00d3724f 100644 --- a/src/common/tools/gen_listings_and_webworkers.ts +++ b/src/common/tools/gen_listings_and_webworkers.ts @@ -12,7 +12,7 @@ and generate Web Worker proxies in OUT_DIR/{suite}/webworker/**/*.worker.js for every .spec.js file. (Note {suite}/webworker/ is reserved for this purpose.) Example: - tools/gen_listings gen/ src/unittests/ src/webgpu/ + tools/gen_listings_and_webworkers gen/ src/unittests/ src/webgpu/ Options: --help Print this message and exit. From 0f173fa38a88796bbb76a314aef54c917c55853c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Beaufort?= Date: Thu, 7 Mar 2024 10:22:38 +0100 Subject: [PATCH 10/22] Address feedback | part 6 --- docs/terms.md | 2 +- src/common/internal/test_suite_listing.ts | 2 +- src/common/tools/gen_listings_and_webworkers.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/terms.md b/docs/terms.md index 032639be577a..0dc6f0ca1701 100644 --- a/docs/terms.md +++ b/docs/terms.md @@ -111,7 +111,7 @@ Each Suite has one Listing File (`suite/listing.[tj]s`), containing a list of th in the suite. In `src/suite/listing.ts`, this is computed dynamically. -In `out/suite/listing.js`, the listing has been pre-baked (by `tools/gen_listings`). +In `out/suite/listing.js`, the listing has been pre-baked (by `tools/gen_listings_and_webworkers`). **Type:** Once `import`ed, `ListingFile` diff --git a/src/common/internal/test_suite_listing.ts b/src/common/internal/test_suite_listing.ts index 2d2b555366e4..c5a0e1144839 100644 --- a/src/common/internal/test_suite_listing.ts +++ b/src/common/internal/test_suite_listing.ts @@ -1,6 +1,6 @@ // A listing of all specs within a single suite. This is the (awaited) type of // `groups` in '{cts,unittests}/listing.ts' and `listing` in the auto-generated -// 'out/{cts,unittests}/listing.js' files (see tools/gen_listings). +// 'out/{cts,unittests}/listing.js' files (see tools/gen_listings_and_webworkers). export type TestSuiteListing = TestSuiteListingEntry[]; export type TestSuiteListingEntry = TestSuiteListingEntrySpec | TestSuiteListingEntryReadme; diff --git a/src/common/tools/gen_listings_and_webworkers.ts b/src/common/tools/gen_listings_and_webworkers.ts index d9df00d3724f..e446936b66cf 100644 --- a/src/common/tools/gen_listings_and_webworkers.ts +++ b/src/common/tools/gen_listings_and_webworkers.ts @@ -5,7 +5,7 @@ import * as process from 'process'; import { crawl } from './crawl.js'; function usage(rc: number): void { - console.error(`Usage: tools/gen_listings [options] [OUT_DIR] [SUITE_DIRS...] + console.error(`Usage: tools/gen_listings_and_webworkers [options] [OUT_DIR] [SUITE_DIRS...] For each suite in SUITE_DIRS, generate listings into OUT_DIR/{suite}/listing.js, and generate Web Worker proxies in OUT_DIR/{suite}/webworker/**/*.worker.js for From 1a6123a52bc3b1011dec79983d8b31d73fa5c98f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Beaufort?= Date: Thu, 7 Mar 2024 11:42:37 +0100 Subject: [PATCH 11/22] Address feedback | part 7 --- src/common/tools/dev_server.ts | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/common/tools/dev_server.ts b/src/common/tools/dev_server.ts index ca52fdc93568..210548e50ab4 100644 --- a/src/common/tools/dev_server.ts +++ b/src/common/tools/dev_server.ts @@ -147,6 +147,19 @@ app.get('/out/:suite([a-zA-Z0-9_-]+)/listing.js', async (req, res, next) => { // Serve all other .js files by fetching the source .ts file and compiling it. app.get('/out/**/*.js', async (req, res, next) => { const jsUrl = path.relative('/out', req.url); + // Worker files are generated on the fly. + if (jsUrl.endsWith('.worker.js')) { + const specUrl = req.url.replace(/\/webworker/, '').replace(/\.worker.js$/, '.spec.js'); + const result = ` + import { g } from '${specUrl}'; + import { wrapTestGroupForWorker } from '/out/common/runtime/helper/wrap_for_worker.js'; + + wrapTestGroupForWorker(g); +`; + res.setHeader('Content-Type', 'application/javascript'); + res.send(result); + } + const tsUrl = jsUrl.replace(/\.js$/, '.ts'); if (compileCache.has(tsUrl)) { res.setHeader('Content-Type', 'application/javascript'); @@ -154,12 +167,10 @@ app.get('/out/**/*.js', async (req, res, next) => { return; } - // I'm not sure if this is the way I should handle it... - const dir = jsUrl.endsWith('worker.js') ? path.resolve(srcDir, '../out') : srcDir; - let absPath = path.join(dir, tsUrl); + let absPath = path.join(srcDir, tsUrl); if (!fs.existsSync(absPath)) { // The .ts file doesn't exist. Try .js file in case this is a .js/.d.ts pair. - absPath = path.join(dir, jsUrl); + absPath = path.join(srcDir, jsUrl); } try { From e3b63ff1e2365c75332970b566e746ba8319410e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Beaufort?= Date: Thu, 7 Mar 2024 11:47:34 +0100 Subject: [PATCH 12/22] Address feedback | part 8 --- src/common/tools/dev_server.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/common/tools/dev_server.ts b/src/common/tools/dev_server.ts index 210548e50ab4..0be334704afe 100644 --- a/src/common/tools/dev_server.ts +++ b/src/common/tools/dev_server.ts @@ -150,11 +150,11 @@ app.get('/out/**/*.js', async (req, res, next) => { // Worker files are generated on the fly. if (jsUrl.endsWith('.worker.js')) { const specUrl = req.url.replace(/\/webworker/, '').replace(/\.worker.js$/, '.spec.js'); - const result = ` - import { g } from '${specUrl}'; - import { wrapTestGroupForWorker } from '/out/common/runtime/helper/wrap_for_worker.js'; + const result = `\ +import { g } from '${specUrl}'; +import { wrapTestGroupForWorker } from '/out/common/runtime/helper/wrap_for_worker.js'; - wrapTestGroupForWorker(g); +wrapTestGroupForWorker(g); `; res.setHeader('Content-Type', 'application/javascript'); res.send(result); From 8730e5579fa350fc22df1b8b52b7939affeb5de0 Mon Sep 17 00:00:00 2001 From: Kai Ninomiya Date: Thu, 7 Mar 2024 14:41:52 -0800 Subject: [PATCH 13/22] Apply suggestions from code review --- src/common/runtime/helper/utils_worker.ts | 2 +- src/common/tools/dev_server.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/common/runtime/helper/utils_worker.ts b/src/common/runtime/helper/utils_worker.ts index 7be4d10a57fc..147c1fa9f83e 100644 --- a/src/common/runtime/helper/utils_worker.ts +++ b/src/common/runtime/helper/utils_worker.ts @@ -4,7 +4,7 @@ import { setDefaultRequestAdapterOptions } from '../../util/navigator_gpu.js'; import { CTSOptions } from './options.js'; -/* +/** * Set config environment for workers with ctsOptions and return a Logger. */ export function setupWorkerEnvironment(ctsOptions: CTSOptions): Logger { diff --git a/src/common/tools/dev_server.ts b/src/common/tools/dev_server.ts index 0be334704afe..3151722a908e 100644 --- a/src/common/tools/dev_server.ts +++ b/src/common/tools/dev_server.ts @@ -158,6 +158,7 @@ wrapTestGroupForWorker(g); `; res.setHeader('Content-Type', 'application/javascript'); res.send(result); + return; } const tsUrl = jsUrl.replace(/\.js$/, '.ts'); From ffff9fdd345989d7fd1c00ab9fcf241cc2db7966 Mon Sep 17 00:00:00 2001 From: Kai Ninomiya Date: Thu, 7 Mar 2024 14:57:44 -0800 Subject: [PATCH 14/22] use WorkerTestRunRequest in the postMessage/onmessage interface --- .../runtime/helper/test_worker-worker.ts | 8 ++---- src/common/runtime/helper/test_worker.ts | 27 ++++++++----------- src/common/runtime/helper/utils_worker.ts | 7 +++++ src/common/runtime/helper/wrap_for_worker.ts | 9 +++---- 4 files changed, 23 insertions(+), 28 deletions(-) diff --git a/src/common/runtime/helper/test_worker-worker.ts b/src/common/runtime/helper/test_worker-worker.ts index 5223d2e8b61e..cb31f4d26388 100644 --- a/src/common/runtime/helper/test_worker-worker.ts +++ b/src/common/runtime/helper/test_worker-worker.ts @@ -1,11 +1,9 @@ import { setBaseResourcePath } from '../../framework/resources.js'; import { DefaultTestFileLoader } from '../../internal/file_loader.js'; import { parseQuery } from '../../internal/query/parseQuery.js'; -import { TestQueryWithExpectation } from '../../internal/query/query.js'; import { assert } from '../../util/util.js'; -import { CTSOptions } from './options.js'; -import { setupWorkerEnvironment } from './utils_worker.js'; +import { setupWorkerEnvironment, WorkerTestRunRequest } from './utils_worker.js'; // Should be WorkerGlobalScope, but importing lib "webworker" conflicts with lib "dom". /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ @@ -16,9 +14,7 @@ const loader = new DefaultTestFileLoader(); setBaseResourcePath('../../../resources'); async function reportTestResults(this: MessagePort | Worker, ev: MessageEvent) { - const query: string = ev.data.query; - const expectations: TestQueryWithExpectation[] = ev.data.expectations; - const ctsOptions: CTSOptions = ev.data.ctsOptions; + const { query, expectations, ctsOptions } = ev.data as WorkerTestRunRequest; const log = setupWorkerEnvironment(ctsOptions); diff --git a/src/common/runtime/helper/test_worker.ts b/src/common/runtime/helper/test_worker.ts index 7a016275813c..fd2c659ba001 100644 --- a/src/common/runtime/helper/test_worker.ts +++ b/src/common/runtime/helper/test_worker.ts @@ -5,12 +5,7 @@ import { TestQueryWithExpectation } from '../../internal/query/query.js'; import { assert } from '../../util/util.js'; import { CTSOptions, kDefaultCTSOptions } from './options.js'; - -interface WorkerTestRunRequest { - rec: TestCaseRecorder; - query: string; - expectations: TestQueryWithExpectation[]; -} +import { WorkerTestRunRequest } from './utils_worker.js'; class TestBaseWorker { protected readonly ctsOptions: CTSOptions; @@ -36,14 +31,17 @@ class TestBaseWorker { async makeRequestAndRecordResult( target: MessagePort | Worker | ServiceWorker, - request: WorkerTestRunRequest + rec: TestCaseRecorder, + query: string, + expectations: TestQueryWithExpectation[] ) { - const { query, expectations, rec } = request; - target.postMessage({ + const request: WorkerTestRunRequest = { query, expectations, ctsOptions: this.ctsOptions, - }); + }; + target.postMessage(request); + const workerResult = await new Promise(resolve => { this.resolvers.set(query, resolve); }); @@ -68,8 +66,7 @@ export class TestDedicatedWorker extends TestBaseWorker { query: string, expectations: TestQueryWithExpectation[] = [] ): Promise { - const request: WorkerTestRunRequest = { rec, query, expectations }; - await this.makeRequestAndRecordResult(this.worker, request); + await this.makeRequestAndRecordResult(this.worker, rec, query, expectations); } } @@ -94,8 +91,7 @@ export class TestSharedWorker extends TestBaseWorker { query: string, expectations: TestQueryWithExpectation[] = [] ): Promise { - const request: WorkerTestRunRequest = { rec, query, expectations }; - await this.makeRequestAndRecordResult(this.port, request); + await this.makeRequestAndRecordResult(this.port, rec, query, expectations); } } @@ -119,8 +115,7 @@ export class TestServiceWorker extends TestBaseWorker { await registration.update(); navigator.serviceWorker.onmessage = ev => this.onmessage(ev); assert(!!registration.active); - const request: WorkerTestRunRequest = { rec, query, expectations }; - await this.makeRequestAndRecordResult(registration.active, request); + await this.makeRequestAndRecordResult(registration.active, rec, query, expectations); void registration.unregister(); } } diff --git a/src/common/runtime/helper/utils_worker.ts b/src/common/runtime/helper/utils_worker.ts index 147c1fa9f83e..c8ca6a2a3a0a 100644 --- a/src/common/runtime/helper/utils_worker.ts +++ b/src/common/runtime/helper/utils_worker.ts @@ -1,9 +1,16 @@ import { globalTestConfig } from '../../framework/test_config.js'; import { Logger } from '../../internal/logging/logger.js'; +import { TestQueryWithExpectation } from '../../internal/query/query.js'; import { setDefaultRequestAdapterOptions } from '../../util/navigator_gpu.js'; import { CTSOptions } from './options.js'; +export interface WorkerTestRunRequest { + query: string; + expectations: TestQueryWithExpectation[]; + ctsOptions: CTSOptions; +} + /** * Set config environment for workers with ctsOptions and return a Logger. */ diff --git a/src/common/runtime/helper/wrap_for_worker.ts b/src/common/runtime/helper/wrap_for_worker.ts index 8124df8ab7a9..1bb357788a20 100644 --- a/src/common/runtime/helper/wrap_for_worker.ts +++ b/src/common/runtime/helper/wrap_for_worker.ts @@ -1,18 +1,15 @@ import { Fixture } from '../../framework/fixture'; import { comparePaths, comparePublicParamsPaths, Ordering } from '../../internal/query/compare.js'; import { parseQuery } from '../../internal/query/parseQuery.js'; -import { TestQuerySingleCase, TestQueryWithExpectation } from '../../internal/query/query.js'; +import { TestQuerySingleCase } from '../../internal/query/query.js'; import { TestGroup } from '../../internal/test_group.js'; import { assert } from '../../util/util.js'; -import { CTSOptions } from './options.js'; -import { setupWorkerEnvironment } from './utils_worker.js'; +import { setupWorkerEnvironment, WorkerTestRunRequest } from './utils_worker.js'; export function wrapTestGroupForWorker(g: TestGroup) { self.onmessage = async (ev: MessageEvent) => { - const query: string = ev.data.query; - const expectations: TestQueryWithExpectation[] = ev.data.expectations; - const ctsOptions: CTSOptions = ev.data.ctsOptions; + const { query, expectations, ctsOptions } = ev.data as WorkerTestRunRequest; const log = setupWorkerEnvironment(ctsOptions); From 4d783048e6df335b9fca484ede4eab1376537970 Mon Sep 17 00:00:00 2001 From: Kai Ninomiya Date: Thu, 7 Mar 2024 15:46:02 -0800 Subject: [PATCH 15/22] Clean up resolvers map --- src/common/runtime/helper/test_worker.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/common/runtime/helper/test_worker.ts b/src/common/runtime/helper/test_worker.ts index fd2c659ba001..724a1185b70d 100644 --- a/src/common/runtime/helper/test_worker.ts +++ b/src/common/runtime/helper/test_worker.ts @@ -24,6 +24,7 @@ class TestBaseWorker { } } this.resolvers.get(query)!(result as LiveTestCaseResult); + this.resolvers.delete(query); // MAINTENANCE_TODO(kainino0x): update the Logger with this result (or don't have a logger and // update the entire results JSON somehow at some point). @@ -43,6 +44,7 @@ class TestBaseWorker { target.postMessage(request); const workerResult = await new Promise(resolve => { + assert(!this.resolvers.has(query), "can't request same query twice simultaneously"); this.resolvers.set(query, resolve); }); rec.injectResult(workerResult); From 0571de702690f11ec973c02ccfc74f9a15dcf9a9 Mon Sep 17 00:00:00 2001 From: Kai Ninomiya Date: Thu, 7 Mar 2024 15:46:22 -0800 Subject: [PATCH 16/22] Use express routing for .worker.js --- src/common/tools/dev_server.ts | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/common/tools/dev_server.ts b/src/common/tools/dev_server.ts index 3151722a908e..8e0e3bdbe656 100644 --- a/src/common/tools/dev_server.ts +++ b/src/common/tools/dev_server.ts @@ -144,23 +144,22 @@ app.get('/out/:suite([a-zA-Z0-9_-]+)/listing.js', async (req, res, next) => { } }); -// Serve all other .js files by fetching the source .ts file and compiling it. -app.get('/out/**/*.js', async (req, res, next) => { - const jsUrl = path.relative('/out', req.url); - // Worker files are generated on the fly. - if (jsUrl.endsWith('.worker.js')) { - const specUrl = req.url.replace(/\/webworker/, '').replace(/\.worker.js$/, '.spec.js'); - const result = `\ -import { g } from '${specUrl}'; +// Serve .worker.js files by generating the necessary wrapper. +app.get('/out/:suite([a-zA-Z0-9_-]+)/webworker/:filepath(*).worker.js', (req, res, next) => { + const { suite, filepath } = req.params; + const result = `\ +import { g } from '/out/${suite}/${filepath}.spec.js'; import { wrapTestGroupForWorker } from '/out/common/runtime/helper/wrap_for_worker.js'; wrapTestGroupForWorker(g); `; - res.setHeader('Content-Type', 'application/javascript'); - res.send(result); - return; - } + res.setHeader('Content-Type', 'application/javascript'); + res.send(result); +}); +// Serve all other .js files by fetching the source .ts file and compiling it. +app.get('/out/**/*.js', async (req, res, next) => { + const jsUrl = path.relative('/out', req.url); const tsUrl = jsUrl.replace(/\.js$/, '.ts'); if (compileCache.has(tsUrl)) { res.setHeader('Content-Type', 'application/javascript'); From 465dd6453ff075511a9850bd3cd53ba5491792c9 Mon Sep 17 00:00:00 2001 From: Kai Ninomiya Date: Thu, 7 Mar 2024 15:53:17 -0800 Subject: [PATCH 17/22] Skip worker tests when run in a worker that can't support them DedicatedWorker can be created from DedicatedWorker, but none of the other nested worker pairs are allowed. --- src/webgpu/web_platform/worker/worker.spec.ts | 33 +++++++++++++------ .../web_platform/worker/worker_launcher.ts | 15 +++++++++ 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/src/webgpu/web_platform/worker/worker.spec.ts b/src/webgpu/web_platform/worker/worker.spec.ts index 1527dd2d2f16..deed5d75e232 100644 --- a/src/webgpu/web_platform/worker/worker.spec.ts +++ b/src/webgpu/web_platform/worker/worker.spec.ts @@ -4,6 +4,9 @@ Tests WebGPU is available in a dedicated worker and a shared worker. Note: The CTS test can be run respectively in a dedicated worker and a shared worker by passing in worker=dedicated and worker=shared as a query parameter. These tests are specifically to check that WebGPU is available in a dedicated worker and a shared worker. + +TODO[2]: Figure out how to make these tests run in service workers (not actually +important unless service workers gain the ability to launch other workers). `; import { Fixture } from '../../../common/framework/fixture.js'; @@ -12,22 +15,26 @@ import { assert } from '../../../common/util/util.js'; export const g = makeTestGroup(Fixture); -// Note: we load worker_launcher dynamically because ts-node support +const isNode = typeof process !== 'undefined' && process?.versions?.node !== undefined; + +// [1]: we load worker_launcher dynamically because ts-node support // is using commonjs which doesn't support import.meta. Further, // we need to put the url in a string and pass the string to import // otherwise typescript tries to parse the file which again, fails. // worker_launcher.js is excluded in node.tsconfig.json. -function isNode(): boolean { - return typeof process !== 'undefined' && process?.versions?.node !== undefined; -} +// [2]: That hack does not work in Service Workers. +const isServiceWorker = globalThis.constructor.name === 'ServiceWorkerGlobalScope'; g.test('dedicated_worker') .desc(`test WebGPU is available in dedicated workers and check for basic functionality`) .fn(async t => { - t.skipIf(isNode(), 'node does not support 100% compatible workers'); + t.skipIf(isNode, 'node does not support 100% compatible workers'); + + t.skipIf(isServiceWorker, 'Service workers do not support this import() hack'); // [2] const url = './worker_launcher.js'; - const { launchDedicatedWorker } = await import(url); + const { launchDedicatedWorker } = await import(url); // [1] + const result = await launchDedicatedWorker(); assert(result.error === undefined, `should be no error from worker but was: ${result.error}`); }); @@ -35,9 +42,12 @@ g.test('dedicated_worker') g.test('shared_worker') .desc(`test WebGPU is available in shared workers and check for basic functionality`) .fn(async t => { - t.skipIf(isNode(), 'node does not support 100% compatible workers'); + t.skipIf(isNode, 'node does not support 100% compatible workers'); + + t.skipIf(isServiceWorker, 'Service workers do not support this import() hack'); // [2] const url = './worker_launcher.js'; - const { launchSharedWorker } = await import(url); + const { launchSharedWorker } = await import(url); // [1] + const result = await launchSharedWorker(); assert(result.error === undefined, `should be no error from worker but was: ${result.error}`); }); @@ -45,9 +55,12 @@ g.test('shared_worker') g.test('service_worker') .desc(`test WebGPU is available in service workers and check for basic functionality`) .fn(async t => { - t.skipIf(isNode(), 'node does not support 100% compatible workers'); + t.skipIf(isNode, 'node does not support 100% compatible workers'); + + t.skipIf(isServiceWorker, 'Service workers do not support this import() hack'); // [2] const url = './worker_launcher.js'; - const { launchServiceWorker } = await import(url); + const { launchServiceWorker } = await import(url); // [1] + const result = await launchServiceWorker(); assert(result.error === undefined, `should be no error from worker but was: ${result.error}`); }); diff --git a/src/webgpu/web_platform/worker/worker_launcher.ts b/src/webgpu/web_platform/worker/worker_launcher.ts index ab2bf82a1c01..4b1d31ae4921 100644 --- a/src/webgpu/web_platform/worker/worker_launcher.ts +++ b/src/webgpu/web_platform/worker/worker_launcher.ts @@ -1,3 +1,4 @@ +import { SkipTestCase } from '../../../common/framework/fixture.js'; import { getDefaultRequestAdapterOptions } from '../../../common/util/navigator_gpu.js'; export type TestResult = { @@ -5,6 +6,10 @@ export type TestResult = { }; export async function launchDedicatedWorker() { + if (typeof Worker === 'undefined') { + throw new SkipTestCase(`Worker undefined in context ${globalThis.constructor.name}`); + } + const selfPath = import.meta.url; const selfPathDir = selfPath.substring(0, selfPath.lastIndexOf('/')); const workerPath = selfPathDir + '/worker.js'; @@ -18,6 +23,10 @@ export async function launchDedicatedWorker() { } export async function launchSharedWorker() { + if (typeof SharedWorker === 'undefined') { + throw new SkipTestCase(`SharedWorker undefined in context ${globalThis.constructor.name}`); + } + const selfPath = import.meta.url; const selfPathDir = selfPath.substring(0, selfPath.lastIndexOf('/')); const workerPath = selfPathDir + '/worker.js'; @@ -35,6 +44,12 @@ export async function launchSharedWorker() { } export async function launchServiceWorker() { + if (typeof navigator === 'undefined' || typeof navigator.serviceWorker === 'undefined') { + throw new SkipTestCase( + `navigator.serviceWorker undefined in context ${globalThis.constructor.name}` + ); + } + const selfPath = import.meta.url; const selfPathDir = selfPath.substring(0, selfPath.lastIndexOf('/')); const serviceWorkerPath = selfPathDir + '/worker.js'; From d66ce41093431cfaceae0c18ada55683be2c0a0a Mon Sep 17 00:00:00 2001 From: Kai Ninomiya Date: Thu, 7 Mar 2024 16:22:21 -0800 Subject: [PATCH 18/22] Clean up all service workers on startup and shutdown --- src/common/runtime/helper/test_worker.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/common/runtime/helper/test_worker.ts b/src/common/runtime/helper/test_worker.ts index 724a1185b70d..8e762a98de44 100644 --- a/src/common/runtime/helper/test_worker.ts +++ b/src/common/runtime/helper/test_worker.ts @@ -7,6 +7,22 @@ import { assert } from '../../util/util.js'; import { CTSOptions, kDefaultCTSOptions } from './options.js'; import { WorkerTestRunRequest } from './utils_worker.js'; +/** Query all currently-registered service workers, and unregister them. */ +function unregisterAllServiceWorkers() { + navigator.serviceWorker.getRegistrations().then(registrations => { + for (const registration of registrations) { + registration.unregister(); + } + }); +} + +// NOTE: This code runs on startup for any runtime with worker support. Here, we use that chance to +// delete any leaked service workers, and register to clean up after ourselves at shutdown. +unregisterAllServiceWorkers(); +window.addEventListener('beforeunload', () => { + unregisterAllServiceWorkers(); +}); + class TestBaseWorker { protected readonly ctsOptions: CTSOptions; protected readonly resolvers = new Map void>(); From 01f8b22bc0624f6fdb11d9872065eda1b0aa9bae Mon Sep 17 00:00:00 2001 From: Kai Ninomiya Date: Thu, 7 Mar 2024 16:44:58 -0800 Subject: [PATCH 19/22] Avoid reinitializing service workers for every single case --- src/common/runtime/helper/test_worker.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/common/runtime/helper/test_worker.ts b/src/common/runtime/helper/test_worker.ts index 8e762a98de44..2c19acd344d4 100644 --- a/src/common/runtime/helper/test_worker.ts +++ b/src/common/runtime/helper/test_worker.ts @@ -127,13 +127,17 @@ export class TestServiceWorker extends TestBaseWorker { const fileName = name.split(',').join('/'); const serviceWorkerPath = `/out/${suite}/webworker/${fileName}.worker.js`; + // If a registration already exists for this path, it will be ignored. const registration = await navigator.serviceWorker.register(serviceWorkerPath, { type: 'module', }); - await registration.update(); + // If this a new registration, it might not be active yet. + while (!registration.active) { + await new Promise(resolve => setTimeout(resolve, 0)); + } + const serviceWorker = registration.active; + navigator.serviceWorker.onmessage = ev => this.onmessage(ev); - assert(!!registration.active); - await this.makeRequestAndRecordResult(registration.active, rec, query, expectations); - void registration.unregister(); + await this.makeRequestAndRecordResult(serviceWorker, rec, query, expectations); } } From 5eb75c3d25c2a007de8c03a2af9bb9e51e4fbb23 Mon Sep 17 00:00:00 2001 From: Kai Ninomiya Date: Thu, 7 Mar 2024 16:54:03 -0800 Subject: [PATCH 20/22] lint fixes --- src/common/runtime/helper/test_worker.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/common/runtime/helper/test_worker.ts b/src/common/runtime/helper/test_worker.ts index 2c19acd344d4..ff33854a4248 100644 --- a/src/common/runtime/helper/test_worker.ts +++ b/src/common/runtime/helper/test_worker.ts @@ -2,6 +2,7 @@ import { LogMessageWithStack } from '../../internal/logging/log_message.js'; import { TransferredTestCaseResult, LiveTestCaseResult } from '../../internal/logging/result.js'; import { TestCaseRecorder } from '../../internal/logging/test_case_recorder.js'; import { TestQueryWithExpectation } from '../../internal/query/query.js'; +import { timeout } from '../../util/timeout.js'; import { assert } from '../../util/util.js'; import { CTSOptions, kDefaultCTSOptions } from './options.js'; @@ -9,9 +10,9 @@ import { WorkerTestRunRequest } from './utils_worker.js'; /** Query all currently-registered service workers, and unregister them. */ function unregisterAllServiceWorkers() { - navigator.serviceWorker.getRegistrations().then(registrations => { + void navigator.serviceWorker.getRegistrations().then(registrations => { for (const registration of registrations) { - registration.unregister(); + void registration.unregister(); } }); } @@ -133,7 +134,7 @@ export class TestServiceWorker extends TestBaseWorker { }); // If this a new registration, it might not be active yet. while (!registration.active) { - await new Promise(resolve => setTimeout(resolve, 0)); + await new Promise(resolve => timeout(resolve, 0)); } const serviceWorker = registration.active; From 4c8178fa1835f77514d33a83eccbd8823763141a Mon Sep 17 00:00:00 2001 From: Kai Ninomiya Date: Fri, 8 Mar 2024 14:18:30 -0800 Subject: [PATCH 21/22] Catch errors in wrapTestGroupForWorker onMessage --- src/common/runtime/helper/wrap_for_worker.ts | 41 ++++++++++++-------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/src/common/runtime/helper/wrap_for_worker.ts b/src/common/runtime/helper/wrap_for_worker.ts index 1bb357788a20..8e206f8399ab 100644 --- a/src/common/runtime/helper/wrap_for_worker.ts +++ b/src/common/runtime/helper/wrap_for_worker.ts @@ -1,4 +1,5 @@ import { Fixture } from '../../framework/fixture'; +import { LogMessageWithStack } from '../../internal/logging/log_message.js'; import { comparePaths, comparePublicParamsPaths, Ordering } from '../../internal/query/compare.js'; import { parseQuery } from '../../internal/query/parseQuery.js'; import { TestQuerySingleCase } from '../../internal/query/query.js'; @@ -10,25 +11,33 @@ import { setupWorkerEnvironment, WorkerTestRunRequest } from './utils_worker.js' export function wrapTestGroupForWorker(g: TestGroup) { self.onmessage = async (ev: MessageEvent) => { const { query, expectations, ctsOptions } = ev.data as WorkerTestRunRequest; + try { + const log = setupWorkerEnvironment(ctsOptions); - const log = setupWorkerEnvironment(ctsOptions); - - const testQuery = parseQuery(query); - assert(testQuery instanceof TestQuerySingleCase); - let testcase = null; - for (const t of g.iterate()) { - if (comparePaths(t.testPath, testQuery.testPathParts) !== Ordering.Equal) { - continue; - } - for (const c of t.iterate(testQuery.params)) { - if (comparePublicParamsPaths(c.id.params, testQuery.params) === Ordering.Equal) { - testcase = c; + const testQuery = parseQuery(query); + assert(testQuery instanceof TestQuerySingleCase); + let testcase = null; + for (const t of g.iterate()) { + if (comparePaths(t.testPath, testQuery.testPathParts) !== Ordering.Equal) { + continue; + } + for (const c of t.iterate(testQuery.params)) { + if (comparePublicParamsPaths(c.id.params, testQuery.params) === Ordering.Equal) { + testcase = c; + } } } + assert(!!testcase, 'testcase not found'); + const [rec, result] = log.record(query); + await testcase.run(rec, testQuery, expectations); + + ev.source?.postMessage({ query, result }); + } catch (thrown) { + const ex = thrown instanceof Error ? thrown : new Error(`${thrown}`); + ev.source?.postMessage({ + query, + result: { status: 'fail', timems: 0, logs: [new LogMessageWithStack('INTERNAL', ex)] }, + }); } - assert(!!testcase); - const [rec, result] = log.record(query); - await testcase.run(rec, testQuery, expectations); - ev.source?.postMessage({ query, result }); }; } From 97e378edee05614d51345dd5541b13f227bd88a5 Mon Sep 17 00:00:00 2001 From: Kai Ninomiya Date: Fri, 8 Mar 2024 14:27:03 -0800 Subject: [PATCH 22/22] Make sure the service worker has the correct URL --- src/common/runtime/helper/test_worker.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/common/runtime/helper/test_worker.ts b/src/common/runtime/helper/test_worker.ts index ff33854a4248..42848106b68e 100644 --- a/src/common/runtime/helper/test_worker.ts +++ b/src/common/runtime/helper/test_worker.ts @@ -126,14 +126,18 @@ export class TestServiceWorker extends TestBaseWorker { ): Promise { const [suite, name] = query.split(':', 2); const fileName = name.split(',').join('/'); - const serviceWorkerPath = `/out/${suite}/webworker/${fileName}.worker.js`; + const serviceWorkerURL = new URL( + `/out/${suite}/webworker/${fileName}.worker.js`, + window.location.href + ).toString(); // If a registration already exists for this path, it will be ignored. - const registration = await navigator.serviceWorker.register(serviceWorkerPath, { + const registration = await navigator.serviceWorker.register(serviceWorkerURL, { type: 'module', }); - // If this a new registration, it might not be active yet. - while (!registration.active) { + // Make sure the registration we just requested is active. (We don't worry about it being + // outdated from a previous page load, because we wipe all service workers on shutdown/startup.) + while (!registration.active || registration.active.scriptURL !== serviceWorkerURL) { await new Promise(resolve => timeout(resolve, 0)); } const serviceWorker = registration.active;