// // benchmark_wota_nota_json.js // // Usage in QuickJS: // qjs benchmark_wota_nota_json.js // // Ensure wota, nota, json, and os are all available, e.g.: var wota = use('wota'); var nota = use('nota'); var json = use('json'); var os = use('os'); // //////////////////////////////////////////////////////////////////////////////// // 1. Setup "libraries" array to easily switch among Wota, Nota, and JSON //////////////////////////////////////////////////////////////////////////////// const libraries = [ { name: "Wota", encode: wota.encode, decode: wota.decode, // Wota produces an ArrayBuffer. We'll count `buffer.byteLength` as size. getSize(encoded) { return encoded.byteLength; } }, { name: "Nota", encode: nota.encode, decode: nota.decode, // Nota also produces an ArrayBuffer: getSize(encoded) { return encoded.byteLength; } }, { name: "JSON", encode: json.encode, decode: json.decode, // JSON produces a JS string. We'll measure its UTF-16 code unit length // as a rough "size". Alternatively, you could convert to UTF-8 for // a more accurate byte size. Here we just use `string.length`. getSize(encodedStr) { return encodedStr.length; } } ]; //////////////////////////////////////////////////////////////////////////////// // 2. Test data sets (similar to wota benchmarks). // Each scenario has { name, data, iterations } //////////////////////////////////////////////////////////////////////////////// const benchmarks = [ { name: "Small Integers", data: [0, 42, -1, 2023], iterations: 100000 }, { name: "Floating point", data: [0.1, 1e-50, 3.14159265359], iterations: 100000 }, { name: "Strings (short, emoji)", data: ["Hello, Wota!", "short", "Emoji: \u{1f600}\u{1f64f}"], iterations: 100000 }, { name: "Small Objects", data: [ { a:1, b:2.2, c:"3", d:false }, { x:42, y:null, z:"test" } ], iterations: 50000 }, { name: "Nested Arrays", data: [ [ [ [1,2], [3,4] ] ], [[[]]], [1, [2, [3, [4]]]] ], iterations: 50000 }, { name: "Large Array (1k integers)", data: [ Array.from({length:1000}, (_, i) => i) ], iterations: 1000 }, { name: "Large Binary Blob (256KB)", data: [ new Uint8Array(256 * 1024).buffer ], iterations: 200 } ]; //////////////////////////////////////////////////////////////////////////////// // 3. Utility: measureTime(fn) => how long fn() takes in seconds. //////////////////////////////////////////////////////////////////////////////// function measureTime(fn) { let start = os.now(); fn(); let end = os.now(); return (end - start); // in seconds } //////////////////////////////////////////////////////////////////////////////// // 4. For each library, we run each benchmark scenario and measure: // - Encoding time (seconds) // - Decoding time (seconds) // - Total encoded size (bytes or code units for JSON) // //////////////////////////////////////////////////////////////////////////////// function runBenchmarkForLibrary(lib, bench) { // We'll encode and decode each item in `bench.data`. // We do 'bench.iterations' times. Then sum up total time. // Pre-store the encoded results for all items so we can measure decode time // in a separate pass. Also measure total size once. let encodedList = []; let totalSize = 0; // 1) Measure ENCODING let encodeTime = measureTime(() => { for (let i = 0; i < bench.iterations; i++) { // For each data item, encode it for (let d of bench.data) { let e = lib.encode(d); // store only in the very first iteration, so we can decode them later // but do not store them every iteration or we blow up memory. if (i === 0) { encodedList.push(e); totalSize += lib.getSize(e); } } } }); // 2) Measure DECODING let decodeTime = measureTime(() => { for (let i = 0; i < bench.iterations; i++) { // decode everything we stored during the first iteration for (let e of encodedList) { let decoded = lib.decode(e); // not verifying correctness here, just measuring speed } } }); return { encodeTime, decodeTime, totalSize }; } //////////////////////////////////////////////////////////////////////////////// // 5. Main driver: run across all benchmarks, for each library. //////////////////////////////////////////////////////////////////////////////// console.log("Benchmark: Wota vs Nota vs JSON"); console.log("================================\n"); for (let bench of benchmarks) { console.log(`SCENARIO: ${bench.name}`); console.log(` Data length: ${bench.data.length} | Iterations: ${bench.iterations}\n`); for (let lib of libraries) { let { encodeTime, decodeTime, totalSize } = runBenchmarkForLibrary(lib, bench); // We'll compute total operations = bench.iterations * bench.data.length let totalOps = bench.iterations * bench.data.length; let encOpsPerSec = (totalOps / encodeTime).toFixed(1); let decOpsPerSec = (totalOps / decodeTime).toFixed(1); console.log(` ${lib.name}:`); console.log(` Encode time: ${encodeTime.toFixed(3)}s => ${encOpsPerSec} encodes/sec`); console.log(` Decode time: ${decodeTime.toFixed(3)}s => ${decOpsPerSec} decodes/sec`); console.log(` Total size: ${totalSize} bytes (or code units for JSON)`); console.log(""); } console.log("---------------------------------------------------------\n"); } console.log("Benchmark complete.\n");