-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #20 from zebp/zebp/benchmarking
chore: add benchmarking suite
- Loading branch information
Showing
14 changed files
with
297 additions
and
91 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
// @ts-check | ||
import * as esbuild from 'esbuild' | ||
import * as path from 'path' | ||
|
||
const OUT_DIR = '../build/test/' | ||
|
||
/** | ||
* Node currently can't import wasm files in the way that we do with Workers, it either throws an | ||
* error if you try to import a wasm file or imports an instantiated wasm instance. Whereas in | ||
* Workers we get a WebAssembly.Module as the default export if we import a wasm file, so this | ||
* plugin is to replicate that behavior in the bundle. | ||
* @type {import('esbuild').Plugin} | ||
*/ | ||
const wasmLoaderPlugin = { | ||
name: 'wasm-module-loader', | ||
setup: (build) => { | ||
build.onResolve({ filter: /\.wasm$/ }, (args) => ({ | ||
path: args.path, | ||
namespace: 'wasm-module', | ||
})) | ||
|
||
build.onLoad({ filter: /.*/, namespace: 'wasm-module' }, (args) => ({ | ||
contents: ` | ||
import * as fs from 'fs'; | ||
import * as path from 'path'; | ||
import * as url from 'url'; | ||
const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); | ||
export default new WebAssembly.Module(fs.readFileSync(path.resolve(__dirname, '${args.path}'))); | ||
`, | ||
})) | ||
}, | ||
} | ||
|
||
esbuild.build({ | ||
bundle: true, | ||
outfile: path.join(OUT_DIR, 'standalone.mjs'), | ||
format: 'esm', | ||
logLevel: 'warning', | ||
entryPoints: ['./driver/standalone.ts'], | ||
plugins: [wasmLoaderPlugin], | ||
platform: 'node', | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import * as child from 'node:child_process' | ||
import * as fs from 'node:fs' | ||
import { cwd } from 'node:process' | ||
import path from 'path/posix' | ||
import type { ExecOptions } from './driver/common' | ||
|
||
const { OUTPUT_DIR } = process.env | ||
const moduleNames = fs | ||
.readdirSync(`${OUTPUT_DIR}/benchmark`) | ||
.map((dirent) => `benchmark/${dirent}`) | ||
|
||
for (const modulePath of moduleNames) { | ||
const prettyName = modulePath.split('/').pop() | ||
if (!prettyName) throw new Error('unreachable') | ||
|
||
test(`${prettyName}`, async () => { | ||
const execOptions: ExecOptions = { | ||
moduleName: prettyName, | ||
asyncify: prettyName.endsWith('.asyncify.wasm'), | ||
fs: {}, | ||
preopens: [], | ||
returnOnExit: false, | ||
} | ||
|
||
// Spawns a child process that runs the wasm so we can isolate the profiling to just that | ||
// specific test case. | ||
const proc = child.execFile( | ||
`node`, | ||
[ | ||
'--experimental-vm-modules', | ||
'--cpu-prof', | ||
'--cpu-prof-dir=./prof', | ||
`--cpu-prof-name=${prettyName}.${Date.now()}.cpuprofile`, | ||
'standalone.mjs', | ||
modulePath, | ||
JSON.stringify(execOptions), | ||
], | ||
{ | ||
encoding: 'utf8', | ||
cwd: OUTPUT_DIR, | ||
} | ||
) | ||
|
||
let stderr = '' | ||
proc.stderr?.on('data', (data) => (stderr += data)) | ||
|
||
const exitCode = await new Promise((resolve) => proc.once('exit', resolve)) | ||
|
||
if (exitCode !== 0) { | ||
console.error(`Child process exited with code ${exitCode}:\n${stderr}`) | ||
} | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import * as fs from 'node:fs/promises' | ||
import { ReadableStream } from 'node:stream/web' | ||
import { exec } from './common' | ||
|
||
const [modulePath, rawOptions] = process.argv.slice(2) | ||
const options = JSON.parse(rawOptions) | ||
|
||
const nulls = new Uint8Array(4096).fill(0) | ||
let written = 0 | ||
|
||
const stdinStream = new ReadableStream<Uint8Array>({ | ||
pull: (controller) => { | ||
if (written > 1_000_000) { | ||
controller.close() | ||
} else { | ||
controller.enqueue(nulls) | ||
written += nulls.byteLength | ||
} | ||
}, | ||
}) | ||
|
||
fs.readFile(modulePath) | ||
.then((wasmBytes) => new WebAssembly.Module(wasmBytes)) | ||
.then((wasmModule) => exec(options, wasmModule, stdinStream as any)) | ||
.then((result) => { | ||
console.log(result.stdout) | ||
console.error(result.stderr) | ||
process.exit(result.status) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { ModuleTable } from '../../build/test/wasm-table' | ||
import { ExecOptions, exec } from './common' | ||
|
||
export default { | ||
async fetch(request: Request) { | ||
const options: ExecOptions = JSON.parse( | ||
atob(request.headers.get('EXEC_OPTIONS')!) | ||
) | ||
|
||
const result = await exec( | ||
options, | ||
ModuleTable[options.moduleName], | ||
request.body ?? undefined | ||
) | ||
return new Response(JSON.stringify(result)) | ||
}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,4 +17,3 @@ dir = "../../build/test/" | |
[[build.upload.rules]] | ||
type = "CompiledWasm" | ||
globs = ["**/*.wasm"] | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.