tricu

A lazy functional language based on Tree Calculus
Log | Files | Refs | README | LICENSE

float_library_acceptance.py (5744B)


      1 #!/usr/bin/env python3
      2 """Check the public contract-composition demo and three bounded usability smokes.
      3 
      4 Uses the preceding library-only boundary run, verifies its source receipt, and
      5 checks fresh-process workloads against an explicit host-local latency budget.
      6 """
      7 import argparse
      8 import json
      9 from pathlib import Path
     10 
     11 from float_boundary import ROOT, Runner, sha, ok, err, nat, pair, tree_list, LEAF, TRUE, expect
     12 from float_ieee import class_words, boundary_pairs
     13 from float_chains import chain_oracle, payload, groups, raw_rows
     14 
     15 
     16 def main():
     17     p=argparse.ArgumentParser(description=__doc__)
     18     p.add_argument('tricu',type=Path);p.add_argument('--boundary-run',type=Path,required=True)
     19     p.add_argument('--directory',type=Path,required=True)
     20     p.add_argument('--support-bundle',type=Path,help='exercise the published demo and library providers')
     21     args=p.parse_args()
     22     prior=json.loads((args.boundary_run/'report.json').read_text())
     23     assert prior['complete'] and prior['library_source']
     24     assert bool(args.support_bundle)==bool(prior.get('artifact_providers'))
     25     if args.support_bundle:
     26         assert sha(args.support_bundle)==prior['artifact_providers']['binary64']['bundle_sha256']
     27     paths={'driver.tri':'test/float_boundary_driver.tri','binary64.tri':'lib/math/binary64.tri','native_math.tri':'lib/math/native.tri'}
     28     paths.update({'binary64_'+f.name:str(f.relative_to(ROOT)) for f in (ROOT/'lib/math/binary64').glob('*.tri')})
     29     assert {k:sha(ROOT/v) for k,v in paths.items()}==prior['sources']
     30     assert sha(args.tricu)==prior['runtime_sha256']
     31     root=args.directory.resolve();root.mkdir(parents=True,exist_ok=False);work=root/'workspace';work.mkdir()
     32     (work/'tricu.workspace').write_text('tricu.workspace.v1\n')
     33     paths.pop('driver.tri');paths.update({'demo.tri':'demos/binary64.tri','base.tri':'lib/base.tri'})
     34     for n,path in paths.items():(work/n).write_bytes((ROOT/path).read_bytes())
     35     (work/'driver.tri').write_text('!import demo as D\n!export batch\ntriage l s f = t (t l s) f\nbatch xs = triage t (_ : t) (a b : t (D.main a) (batch b)) xs\n')
     36     runner=Runner(args.tricu,root,1200,memory_mib=2048)
     37     report=dict(complete=False,sources={n:sha(work/n) for n in [*paths,'driver.tri']},harness_sha256=sha(Path(__file__)),
     38                 runtime_sha256=sha(args.tricu),boundary_bundle_sha256=prior['bundle_sha256'],checks=0,smokes=[])
     39     try:
     40         if args.support_bundle:
     41             from float_fixture import stage_providers
     42             report['artifact_providers']=stage_providers(runner,work,args.support_bundle,['demos_binary64'])
     43             (work/'demo.tri').write_bytes((work/'demos_binary64.tri').read_bytes())
     44         report['workspace_sources']={p.name:sha(p) for p in work.glob('*.tri')}
     45         tool=runner.imported(ROOT/'bootstrap/build-stable.arboricx','compiler');bundle=root/'demo.arboricx'
     46         runner.run('compile',['compile','--file',work/'driver.tri','--toolchain',tool,'--tool-store',runner.store,
     47             '--store',runner.store,'--output',bundle,'--compile-timeout','240'],270)
     48         pin=runner.imported(bundle,'demo');report['demo_bundle_sha256']=sha(bundle)
     49         def invoke(label,pin,name,raw,wanted,smoke=False):
     50             file=root/(label+'.input.tree');file.write_bytes(raw)
     51             actual=runner.invoke(label,pin,name,['--arg-tree-file',file,'--profile-full-result'])
     52             expect(actual,wanted,label)
     53             if smoke:
     54                 points={v['profile']:v for line in (root/(label+'.log')).read_text().splitlines() if line.startswith('{') for v in [json.loads(line)]}
     55                 start,finish=points['invoke-begin-1'],points['force-end-1']
     56                 elapsed=(finish['wall_ns']-start['wall_ns'])/1e9
     57                 report['smokes'].append(dict(name=label,seconds=elapsed,allocated_bytes=finish['allocated_bytes']-start['allocated_bytes'],
     58                     maximum_live_bytes=runner.records[-1]['rts_process']['maximum_live_bytes'],budget_seconds=2,within_budget=elapsed<=2))
     59                 assert elapsed<=2,(label,'local usability smoke budget exceeded')
     60         def expected(a,b):return ok(payload(chain_oracle((a,[b,a],[(2,0),(0,1)]))))
     61         pairs=list(dict.fromkeys([(a,b) for a in class_words() for b in class_words()]+boundary_pairs()))
     62         for start in range(0,len(pairs),12):
     63             batch=pairs[start:start+12]
     64             invoke('demo-'+str(start),pin,'batch',tree_list([pair(nat(a),nat(b)) for a,b in batch]),tree_list([expected(a,b) for a,b in batch]))
     65         report['checks']+=len(pairs)
     66         not_pair=pair(LEAF,pair(tree_list([nat(ord(c)) for c in 'not a pair']),LEAF))
     67         invalid=[LEAF,TRUE,pair(TRUE,nat(1)),pair(nat(1),nat(1<<64))]
     68         invoke('demo-errors',pin,'batch',tree_list(invalid),tree_list([not_pair,not_pair,err(),err()]))
     69         report['checks']+=len(invalid)
     70         small=[(0x3ff0000000000000,0x4000000000000000),(0x3fe0000000000000,0x3ff0000000000000),
     71                (0xbff0000000000000,0x3fe0000000000000),(0,0x4000000000000000)]
     72         invoke('four-affine-values',pin,'batch',tree_list([pair(nat(a),nat(b)) for a,b in small]),
     73                tree_list([expected(a,b) for a,b in small]),True)
     74         old_bundle=args.boundary_run/'boundary.arboricx';assert sha(old_bundle)==prior['bundle_sha256']
     75         chain_pin=runner.imported(old_bundle,'chains')
     76         for name in ['add-reuse-16','divide-reuse-4']:
     77             rows=groups()[name]
     78             invoke(name,chain_pin,'chains',raw_rows(rows),tree_list([payload(chain_oracle(row)) for row in rows]),True)
     79         report['complete']=True
     80         print(json.dumps(report['smokes'],indent=2))
     81     finally:(root/'report.json').write_text(json.dumps(report,indent=2)+'\n')
     82 
     83 if __name__=='__main__':main()