diff --git a/benchmarks/.gitignore b/benchmarks/.gitignore index 07e6e47..ad08405 100644 --- a/benchmarks/.gitignore +++ b/benchmarks/.gitignore @@ -1 +1,2 @@ /node_modules +/results.csv diff --git a/benchmarks/index.html b/benchmarks/index.html index 5bffce6..8eb8a64 100644 --- a/benchmarks/index.html +++ b/benchmarks/index.html @@ -1,97 +1,40 @@ - - - -

 
+
+
+
diff --git a/benchmarks/index.mjs b/benchmarks/index.mjs
index ec1d11a..e50d10a 100644
--- a/benchmarks/index.mjs
+++ b/benchmarks/index.mjs
@@ -1,46 +1,73 @@
-import Benchmark from 'benchmark';
-import { readdirSync, readFileSync } from 'fs';
-import prettyBytes from 'pretty-bytes';
-import { fileSync as brotliSize } from 'brotli-size';
-import { createRequire } from 'module';
-import { inspect } from 'util';
-
-const { Suite } = Benchmark;
-const require = createRequire(import.meta.url);
+const { Suite } = globalThis.Benchmark ?? (await import('benchmark')).default;
 
 let suiteOps = {
   parse: {},
   serialize: {}
 };
 
-const libs = readdirSync('pkg').map(dir => ({
-  name: dir,
-  impl: require(`./pkg/${dir}`)
-}));
+const libs = await Promise.all(
+  ['serde-wasm-bindgen', 'serde-json', 'serde-wasm-bindgen-reftypes']
+    .map(async dir => {
+      try {
+        const impl = await import(`./pkg/${dir}/serde_wasm_bindgen_benches.js`);
+        await impl.default(); // Init Wasm
+        return { name: dir, impl };
+      } catch (err) {
+        console.warn(err);
+        return null;
+      }
+    })
+    .filter(Boolean)
+);
+
+let readFile,
+  filter;
+
+const isNode = typeof process !== 'undefined';
+
+if (isNode) {
+  const prettyBytes = (await import('pretty-bytes')).default;
+  const brotliSize = await import('brotli-size');
+
+  console.log('=== Sizes ===');
+  for (let { name } of libs) {
+    const [js, wasm] = [
+      'serde_wasm_bindgen_benches.js',
+      'serde_wasm_bindgen_benches_bg.wasm'
+    ].map(file => prettyBytes(brotliSize.fileSync(`pkg/${name}/${file}`)));
+
+    console.log(`${name}: JS = ${js}, Wasm = ${wasm}`);
+  }
+  console.log();
 
-console.log('=== Sizes ===');
-for (let { name } of libs) {
-  const [js, wasm] = [
-    'serde_wasm_bindgen_benches.js',
-    'serde_wasm_bindgen_benches_bg.wasm'
-  ].map(file => prettyBytes(brotliSize(`pkg/${name}/${file}`)));
+  const readFileImpl = (await import('fs/promises')).readFile;
+  readFile = name => readFileImpl(name, 'utf8');
 
-  console.log(`${name}: JS = ${js}, Wasm = ${wasm}`);
+  filter = process.argv[2];
+} else {
+  readFile = name =>
+    fetch(name).then(res => {
+      if (!res.ok) {
+        throw new Error(`Failed to fetch ${name}`);
+      }
+      return res.text();
+    });
+
+  filter = new URLSearchParams(location.search).get('filter');
 }
-console.log();
 
-function loadData(name) {
-  return JSON.parse(readFileSync(`./data/${name}.json`, 'utf8'));
+filter = new RegExp(filter ?? '(?:)', 'i');
+
+async function loadData(name) {
+  return JSON.parse(await readFile(`./data/${name}.json`, 'utf8'));
 }
 
 const datasets = {
-  Canada: loadData('canada'),
-  CitmCatalog: loadData('citm_catalog'),
-  Twitter: loadData('twitter')
+  Canada: await loadData('canada'),
+  CitmCatalog: await loadData('citm_catalog'),
+  Twitter: await loadData('twitter')
 };
 
-let filter = new RegExp(process.argv[2] || '(?:)');
-
 for (let { name: libName, impl } of libs) {
   for (let [dataName, json] of Object.entries(datasets)) {
     let { parse } = impl[dataName];
@@ -68,15 +95,35 @@ for (let { name: libName, impl } of libs) {
 
 console.log('=== Benchmarks ===');
 
+let csv = '';
+
 for (let [op, suites] of Object.entries(suiteOps)) {
   console.group(op);
   for (let suite of Object.values(suites)) {
     console.group(suite.name);
-    suite
-      .on('error', event => console.error(event.target.error))
-      .on('cycle', event => console.log(event.target.toString()))
-      .run();
+    await new Promise((resolve, reject) => {
+      suite
+        .on('error', event => reject(event.target.error))
+        .on('cycle', event => {
+          console.log(event.target.toString());
+          csv += `${op},${suite.name},${event.target.name},${event.target.hz}\n`;
+        })
+        .on('complete', resolve)
+        .run({
+          async: true
+        });
+    });
     console.groupEnd();
   }
   console.groupEnd();
 }
+
+if (isNode) {
+  (await import('fs')).writeFileSync('results.csv', csv);
+} else {
+  let csvLink = document.createElement('a');
+  csvLink.href = URL.createObjectURL(new Blob([csv], { type: 'text/csv' }));
+  csvLink.download = 'results.csv';
+  csvLink.textContent = 'Download CSV';
+  document.body.append('Done! ', csvLink);
+}
diff --git a/benchmarks/package.json b/benchmarks/package.json
index 95bc87b..9f16f40 100644
--- a/benchmarks/package.json
+++ b/benchmarks/package.json
@@ -9,10 +9,10 @@
     "pretty-bytes": "^6.0.0"
   },
   "scripts": {
-    "build:swb": "wasm-pack build -t nodejs --out-dir pkg/serde-wasm-bindgen -- --features serde-wasm-bindgen",
-    "build:swb-reftypes": "cross-env RUSTFLAGS=\"-C target-feature=+reference-types\" WASM_BINDGEN_EXTERNREF=1 wasm-pack build -t nodejs --out-dir pkg/serde-wasm-bindgen-reftypes -- --features serde-wasm-bindgen",
-    "build:json": "wasm-pack build -t nodejs --out-dir pkg/serde-json -- --features serde-json",
-    "build:msgpack": "wasm-pack build -t nodejs --out-dir pkg/msgpack -- --features msgpack",
+    "build:swb": "wasm-pack build -t web --out-dir pkg/serde-wasm-bindgen -- --features serde-wasm-bindgen",
+    "build:swb-reftypes": "cross-env RUSTFLAGS=\"-C target-feature=+reference-types\" WASM_BINDGEN_EXTERNREF=1 wasm-pack build -t web --out-dir pkg/serde-wasm-bindgen-reftypes -- --features serde-wasm-bindgen",
+    "build:json": "wasm-pack build -t web --out-dir pkg/serde-json -- --features serde-json",
+    "build:msgpack": "wasm-pack build -t web --out-dir pkg/msgpack -- --features msgpack",
     "build": "npm run build:swb && npm run build:swb-reftypes && npm run build:json",
     "test": "node index.mjs"
   }