tricu

An interpreted language for exploring Tree Calculus
Log | Files | Refs | README | LICENSE

preview-compare.mjs (2773B)


      1 // Compare the same 128-node unary tree: no sharing/expansion advantage hidden
      2 // in the baseline. Every iteration checks the complete shape in either format.
      3 import assert from 'node:assert/strict';
      4 import {readFile,writeFile} from 'node:fs/promises';
      5 import {spawnSync} from 'node:child_process';
      6 import {createHash} from 'node:crypto';
      7 import {cpus} from 'node:os';
      8 import {WasmRuntime} from './runtime.mjs';
      9 import {Graph} from '../demo-site/dist/graph.js';
     10 const [wasmPath,output,mode,pressureArg]=process.argv.slice(2);
     11 const tree='1'.repeat(127)+'0',iterations=100;
     12 if(mode) {
     13   const pressure=Number(pressureArg);
     14   const g=mode==='js'?new Graph({fuel:Infinity}):await WasmRuntime.create(await readFile(wasmPath));
     15   const root=g.fromTernary(tree);
     16   // Extra owned roots simulate a retained host session. JS has no root-table
     17   // scan in this path, but retain equivalent host references for comparison.
     18   const retained=Array.from({length:pressure},()=>mode==='js'?g.leaf:g.retain(g.leaf));
     19   const before=mode==='js'?null:g.stats().owned;
     20   const start=performance.now();
     21   for(let i=0;i<iterations;i++) {
     22     if(mode==='wasm-batch') {
     23       const p=g.preview(root,128);
     24       assert.equal(p.truncated,false);assert.equal(p.nodes.length,128);
     25       for(let j=0;j<128;j++)assert.deepEqual(p.nodes[j],{id:j,kind:j===127?'leaf':'stem',children:j===127?[]:[j+1]});
     26     } else assert.equal(g.toTernary(root),tree);
     27   }
     28   const ms=performance.now()-start;
     29   if(mode!=='js')assert.equal(g.stats().owned,before);
     30   assert.equal(retained.length,pressure);
     31   console.log(JSON.stringify({mode,pressure,iterations,ms,perSnapshotMs:ms/iterations,peakRssKiB:process.resourceUsage().maxRSS}));
     32   g.dispose?.();
     33 } else {
     34   const samples=[];
     35   for(const pressure of [0,2000])for(let round=0;round<3;round++) {
     36     for(const mode of round%2?['wasm-batch','wasm-node','js']:['js','wasm-node','wasm-batch']) {
     37       const child=spawnSync(process.execPath,[import.meta.filename,wasmPath,'-',mode,String(pressure)],{encoding:'utf8',timeout:60_000});
     38       if(child.error||child.status!==0)throw new Error(`${mode}: ${child.error??child.stderr}`);
     39       samples.push({...JSON.parse(child.stdout),round});
     40     }
     41   }
     42   await writeFile(output,JSON.stringify({schema:1,node:process.version,cpu:cpus()[0]?.model,
     43     wasmSha256:createHash('sha256').update(await readFile(wasmPath)).digest('hex'),tree, samples},null,2)+'\n');
     44   for(const pressure of [0,2000]) {
     45     const median=mode=>samples.filter(s=>s.mode===mode&&s.pressure===pressure).map(s=>s.perSnapshotMs).sort((a,b)=>a-b)[1];
     46     console.log(`128-node inspection (${pressure} extra roots): JS ${median('js').toFixed(3)} ms; WASM/node ${median('wasm-node').toFixed(3)} ms; WASM/batch ${median('wasm-batch').toFixed(3)} ms`);
     47   }
     48 }