183 lines
5.5 KiB
JavaScript
183 lines
5.5 KiB
JavaScript
//
|
|
// 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");
|