diff --git a/build.js b/build.js index a9373d6..8f59ea5 100755 --- a/build.js +++ b/build.js @@ -136,7 +136,7 @@ if (watch) { } }).listen(8080); - console.log("listening on port 8080"); + console.log("listening on http://localhost:8080"); const webCtx = await esbuild.context(webBuildOptions); webCtx.watch(); diff --git a/src/benchmarks/benchmarks.js b/src/benchmarks/benchmarks.js index 4d1c60a..2797770 100644 --- a/src/benchmarks/benchmarks.js +++ b/src/benchmarks/benchmarks.js @@ -1,29 +1,29 @@ -import mandelbrot from "./mandelbrot.tal"; import Uxn from "../uxn"; +import suite from "./suite"; const DEV_OFFSET = 0x10200; -const PROGRAM_OFFSET = 0x100; document.body.innerHTML = `

Uxn.wasm Benchmarks

- - +
`; const startButtonEl = document.getElementById("startButton"); -const mandelbrotResultsEl = document.getElementById("mandelbrotResults"); +const resultsEl = document.getElementById("results"); -function runMandelbrot(uxn) { - uxn.load(mandelbrot); - uxn.eval(PROGRAM_OFFSET); -} +startButtonEl.onclick = async () => { + startButtonEl.disabled = true; + resultsEl.replaceChildren(); + for (const b of suite) { + const trEl = document.createElement("table"); + resultsEl.appendChild(trEl); + const thEl = document.createElement("th"); + thEl.appendChild(document.createTextNode(b.name)); + trEl.appendChild(thEl); -async function runMandelbrotBenchmark() { - try { - startButtonEl.disabled = true; const uxn = new Uxn(); await uxn.init({ deo: () => {}, @@ -31,21 +31,25 @@ async function runMandelbrotBenchmark() { return uxn.ram[DEV_OFFSET + port]; }, }); - mandelbrotResultsEl.innerHTML = "Mandelbrot"; + for (let i = 0; i < 5; i++) { - const el = document.createElement("td"); - mandelbrotResultsEl.appendChild(el); - el.appendChild(document.createTextNode("⌛️")); - const t1 = performance.now(); - runMandelbrot(uxn); - const t2 = performance.now(); - el.innerHTML = ((t2 - t1) / 1000.0).toFixed(2) + "s"; + const tdEl = document.createElement("td"); + const valueEl = document.createTextNode("⌛️"); + tdEl.appendChild(valueEl); + trEl.appendChild(tdEl); + let value; + + try { + const t1 = performance.now(); + b.run(uxn); + const t2 = performance.now(); + value = ((t2 - t1) / 1000.0).toFixed(2) + "s"; + } catch (e) { + console.error(e); + value = "error: " + e; + } + tdEl.replaceChild(document.createTextNode(value), valueEl); } - } finally { - startButtonEl.disabled = false; } -} - -startButtonEl.onclick = () => { - runMandelbrotBenchmark(); + startButtonEl.disabled = false; }; diff --git a/src/benchmarks/benchmarks.node.js b/src/benchmarks/benchmarks.node.js new file mode 100644 index 0000000..d6fe2f4 --- /dev/null +++ b/src/benchmarks/benchmarks.node.js @@ -0,0 +1,25 @@ +const suite = require("./suite").default; +const Uxn = require("../uxn"); + +const DEV_OFFSET = 0x10200; + +(async () => { + const uxn = new Uxn(); + await uxn.init({ + deo: () => {}, + dei: (port) => { + return uxn.ram[DEV_OFFSET + port]; + }, + }); + for (const b of suite) { + console.log(b.name); + for (let i = 0; i < 5; i++) { + let value; + const t1 = performance.now(); + b.run(uxn); + const t2 = performance.now(); + value = ((t2 - t1) / 1000.0).toFixed(2) + "s"; + console.log(` run ${i + 1}: ` + value); + } + } +})(); diff --git a/src/benchmarks/suite.js b/src/benchmarks/suite.js new file mode 100644 index 0000000..710a41c --- /dev/null +++ b/src/benchmarks/suite.js @@ -0,0 +1,13 @@ +import mandelbrot from "./mandelbrot.tal"; + +const PROGRAM_OFFSET = 0x100; + +export default [ + { + name: "mandelbrot", + run: (uxn) => { + uxn.load(mandelbrot); + uxn.eval(PROGRAM_OFFSET); + }, + }, +]; diff --git a/test.js b/test.js index ebc7d86..1893f32 100755 --- a/test.js +++ b/test.js @@ -8,11 +8,15 @@ const { uxntalPlugin } = require("./scripts/esbuild/uxntal"); const Mocha = require("mocha"); let watch = false; +let benchmarks = false; for (const arg of process.argv.slice(2)) { switch (arg) { case "--watch": watch = true; break; + case "--benchmarks": + benchmarks = true; + break; } } @@ -26,7 +30,6 @@ function runTests() { const buildOptions = { bundle: true, logLevel: "warning", - entryPoints: [path.join(__dirname, "src", "tests", "tests.node")], target: "node17", outdir: path.join(__dirname, "build"), external: ["fs", "stream", "util", "events", "path"], @@ -36,11 +39,15 @@ const buildOptions = { ".rom": "binary", }, sourcemap: true, - plugins: [ - wasmTextPlugin({ debug: true }), - uxntalPlugin(), + plugins: [wasmTextPlugin({ debug: true }), uxntalPlugin()], +}; + +const testBuildOptions = { + ...buildOptions, + entryPoints: [path.join(__dirname, "src", "tests", "tests.node")], + plugins: buildOptions.plugins.concat([ { - name: "watch", + name: "runTests", setup(build) { build.onEnd((result) => { if (result.errors.length > 0) { @@ -50,14 +57,37 @@ const buildOptions = { }); }, }, - ], + ]), }; -if (watch) { - (async () => { - const ctx = await esbuild.context(buildOptions); - ctx.watch(); - })(); +const benchmarkBuildOptions = { + ...buildOptions, + entryPoints: [path.join(__dirname, "src", "benchmarks", "benchmarks.node")], + plugins: buildOptions.plugins.concat([ + { + name: "runBenchmarks", + setup(build) { + build.onEnd((result) => { + if (result.errors.length > 0) { + return; + } + delete require.cache[path.join(__dirname, "build", "benchmarks.js")]; + require("./build/benchmarks.js"); + }); + }, + }, + ]), +}; + +if (benchmarks) { + esbuild.build(benchmarkBuildOptions); } else { - esbuild.build(buildOptions); + if (watch) { + (async () => { + const ctx = await esbuild.context(testBuildOptions); + ctx.watch(); + })(); + } else { + esbuild.build(testBuildOptions); + } }