demo-cost.mjs (2562B)
1 // Opt-in deterministic work/allocation screen, not a wall-time/RAM benchmark. 2 // Supply an independently retained prior site directory; never rewrite its pins. 3 import assert from 'node:assert/strict'; 4 import {readFile} from 'node:fs/promises'; 5 import {resolve,join} from 'node:path'; 6 import {fileURLToPath} from 'node:url'; 7 import {createHash} from 'node:crypto'; 8 import {Graph} from '../dist/graph.js'; 9 import {decodeBundle,loadBundle} from '../dist/bundle.js'; 10 import {PACKAGE_BUDGET} from './budgets.mjs'; 11 import {PACKAGE_COLLECTION} from '../dist/execution.js'; 12 import {runIO} from '../dist/io.js'; 13 const current=fileURLToPath(new URL('../',import.meta.url)); 14 if(!process.argv[2])throw Error('Select the retained reference site directory'); 15 async function measure(directory){ 16 const data=JSON.parse(await readFile(join(directory,'demos.json'))),result={}; 17 for(const [name,demo] of Object.entries(data.demos)){ 18 const bytes=await readFile(join(directory,'bundles',demo.hash+'.arboricx')); 19 assert.equal(createHash('sha256').update(bytes).digest('hex'),demo.hash); 20 const bundle=decodeBundle(bytes);const cases=[]; 21 for(const c of demo.haskellCases){ 22 const g=new Graph(PACKAGE_BUDGET,PACKAGE_COLLECTION),exports=loadBundle(g,bundle); 23 let output=g.apply(exports.get(c.export),c.arguments.map(tree=>g.fromTernary(tree))),terminal=''; 24 if(demo.mode==='io')output=await runIO(g,output,{ 25 before:async()=>{},after(){},running(){},read:async()=>c.input,write(text){terminal+=text;} 26 },true); 27 assert.equal(g.toTernary(output),c.result);assert.equal(terminal,c.terminal); 28 cases.push({key:JSON.stringify([c.export,c.arguments,c.input,c.result,c.terminal]),...g.stats}); 29 } 30 result[name]={hash:demo.hash,bytes:bytes.length,cases}; 31 } 32 return {compiler:data.compilerBundleSha256,demos:result}; 33 } 34 const before=await measure(resolve(process.argv[2])),after=await measure(current),summary={}; 35 for(const [name,old] of Object.entries(before.demos)){ 36 const next=after.demos[name];let workBefore=0,workAfter=0,allocationsBefore=0,allocationsAfter=0; 37 for(const c of old.cases){ 38 const n=next.cases.find(n=>n.key===c.key);assert.ok(n,`missing independent reference case: ${name}`); 39 workBefore+=c.work;workAfter+=n.work;allocationsBefore+=c.allocations;allocationsAfter+=n.allocations; 40 } 41 summary[name]={commonCases:old.cases.length,bytesBefore:old.bytes,bytesAfter:next.bytes, 42 workBefore,workAfter,allocationsBefore,allocationsAfter}; 43 } 44 console.log(JSON.stringify({summary,before,after},null,2));