binding_compiler_small.py (7134B)
1 #!/usr/bin/env python3 2 """Bounded standalone integration/measurement after the cold-workspace timeout.""" 3 import argparse,json,random,statistics,time 4 from pathlib import Path 5 from binding_substitution import ROOT,HELPERS 6 from abstraction_binding_model import programs,source 7 from float_multiply import Runner,sha 8 from bundle_dag import Intern,read 9 from base_workloads import encode as nat 10 from http_headers import LEAF,TRUE,pair,tree_list,expect 11 12 13 def main(): 14 p=argparse.ArgumentParser(description=__doc__) 15 p.add_argument('tricu',type=Path);p.add_argument('--candidate',type=Path,required=True) 16 p.add_argument('--directory',type=Path,required=True);args=p.parse_args() 17 candidate=args.candidate.resolve();prior=json.loads((candidate/'report.json').read_text()) 18 assert prior['complete'] and sha(candidate/'candidate.arboricx')==prior['candidate_sha256'] 19 root=args.directory.resolve();root.mkdir(parents=True,exist_ok=False) 20 driver=root/'driver.tri' 21 driver.write_text(HELPERS+'\n'+'\n'.join(name+' = '+source(expr) for name,expr in programs().items())+''' 22 map f xs = triage t (_ : t) (a b : t (f a) (map f b)) xs 23 branches xs = map (row : branchBound (head row) (tail row)) xs 24 adders xs = map (row : adderBound (head row) (head (tail row)) (tail (tail row))) xs 25 copies xs = map sharedBound xs 26 partialBranch _ = branchNegatedHead branchBound 27 partialCarryZero _ = adderKnownCarryZero adderBound 28 partialCarryOne _ = adderKnownCarryOne adderBound 29 ''') 30 runner=Runner(args.tricu,root,480,memory_mib=2048) 31 report=dict(complete=False,scope='standalone-module-not-cold-arithmetic-workspace', 32 runtime_sha256=sha(args.tricu),candidate_report_sha256=sha(candidate/'report.json'), 33 harness_sha256=sha(Path(__file__)),source_sha256=sha(driver),compilation=[],samples=[],checks=[]) 34 try: 35 tools={role:runner.imported(path,role) for role,path in [('accepted',ROOT/'bootstrap/build-stable.arboricx'),('candidate',candidate/'candidate.arboricx')]} 36 bundles={};rng=random.Random(5150) 37 for repeat in range(5): 38 order=list(tools);rng.shuffle(order) 39 for role in order: 40 label=f'compile-{repeat}-{role}';out=root/(label+'.arboricx') 41 start=time.monotonic() 42 runner.run(label,['compile','--file',driver,'--toolchain',tools[role],'--tool-store',runner.store, 43 '--store',root/(label+'-store'),'--output',out,'--compile-timeout','45'],60) 44 report['compilation'].append(dict(role=role,repeat=repeat,wall_seconds=time.monotonic()-start, 45 rts=runner.records[-1]['rts_process'])) 46 if role in bundles:assert bundles[role].read_bytes()==out.read_bytes() 47 bundles[role]=out 48 intern=Intern();graphs={};pins={} 49 for role,bundle in bundles.items(): 50 _,_,nodes,exports,_=read(bundle);ids=intern.graph(nodes) 51 graphs[role]={name:ids[index] for name,index in exports.items()} 52 pins[role]=runner.imported(bundle,'import-'+role) 53 old,new=graphs['accepted'],graphs['candidate'] 54 report['changed_controls']=[] 55 for name in programs(): 56 if name in ['singleBound','branchBound','adderBound']: 57 assert new[name]==old[name.replace('Bound','Inline')] 58 report['changed_controls'].append(name) 59 else:assert new[name]==old[name],name 60 report['unchanged_controls']=15 61 def invoke(role,name,raw,wanted,label,measure=False): 62 path=root/(label+'.input.tree');path.write_bytes(raw) 63 actual=runner.invoke(label,pins[role],name,['--arg-tree-file',path]+(['--profile-full-result'] if measure else [])) 64 expect(actual,wanted,label) 65 if not measure:report['checks'].append(dict(role=role,name=name));return 66 points={r['profile']:r for line in (root/(label+'.log')).read_text().splitlines() 67 if line.startswith('{') for r in [json.loads(line)]} 68 a,b=points['invoke-begin-1'],points['force-end-1'] 69 return dict(wall_ns=b['wall_ns']-a['wall_ns'],allocated_bytes=b['allocated_bytes']-a['allocated_bytes']) 70 for role in tools: 71 for name,wanted in [('partialBranch',LEAF),('partialCarryZero',LEAF),('partialCarryOne',TRUE),('unusedBound',LEAF)]: 72 invoke(role,name,LEAF,wanted,'partial-'+role+name) 73 for name,arg in [('closureBound',LEAF),('closedBranchBound',TRUE)]: 74 try:invoke(role,name,arg,LEAF,'demand-'+role+name);raise AssertionError('expected timeout') 75 except RuntimeError as error: 76 if str(error)!='wall-time guard exceeded':raise 77 report['checks'].append(dict(role=role,name=name,outcome='expected-timeout')) 78 flags=[(bool(i&1),bool(i&2)) for i in range(1024)] 79 boolean=lambda b:TRUE if b else LEAF 80 rows=[(bool(i&1),bool(i&2),bool(i&4)) for i in range(1024)] 81 xs=list(range(128));copied=tree_list([b'\1'+nat(x) for x in xs]) 82 workloads={ 83 'branches':(tree_list([pair(boolean(a),boolean(b)) for a,b in flags]), 84 tree_list([pair(boolean(not b),boolean(b)) if a else pair(boolean(b),boolean(not b)) for a,b in flags])), 85 'adders':(tree_list([pair(boolean(a),pair(boolean(b),boolean(c))) for a,b,c in rows]), 86 tree_list([pair(boolean((a+b+c)%2),boolean(a+b+c>=2)) for a,b,c in rows])), 87 'copies':(nat([xs]*4),tree_list([pair(copied,copied)]*4))} 88 for repeat in range(5): 89 jobs=[(role,name) for role in tools for name in workloads];rng.shuffle(jobs) 90 for role,name in jobs: 91 raw,wanted=workloads[name] 92 values=invoke(role,name,raw,wanted,f'time-{repeat}-{role}-{name}',True) 93 report['samples'].append(dict(role=role,name=name,repeat=repeat,**values)) 94 report['runtime']=[] 95 for name in workloads: 96 values={role:{key:statistics.median(r[key] for r in report['samples'] if r['role']==role and r['name']==name and r['repeat']>0) 97 for key in ['wall_ns','allocated_bytes']} for role in tools} 98 report['runtime'].append(dict(name=name,medians=values,ratios={k:values['candidate'][k]/values['accepted'][k] for k in values['accepted']})) 99 values={role:dict(wall_seconds=statistics.median(r['wall_seconds'] for r in report['compilation'] if r['role']==role and r['repeat']>0), 100 allocated_bytes=statistics.median(r['rts']['allocated_bytes'] for r in report['compilation'] if r['role']==role and r['repeat']>0)) for role in tools} 101 report['compile_summary']=dict(medians=values,ratios={k:values['candidate'][k]/values['accepted'][k] for k in values['accepted']}) 102 report['complete']=True;print(json.dumps(dict(compile=report['compile_summary'],runtime=report['runtime']),indent=2)) 103 finally:(root/'report.json').write_text(json.dumps(report,indent=2)+'\n') 104 105 106 if __name__=='__main__':main()