tricu

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

binding_failure_cold.py (4557B)


      1 #!/usr/bin/env python3
      2 """One bounded cold pair with retained timeout logs, CPU and receipt progress."""
      3 import argparse,json,os,signal,subprocess,time
      4 from pathlib import Path
      5 from process_rss import ChildRSS
      6 from float_multiply import Runner,sha
      7 from binding_substitution import ROOT
      8 from rts_metrics import parse_rts_stats
      9 
     10 
     11 def main():
     12     p=argparse.ArgumentParser(description=__doc__)
     13     p.add_argument('tricu',type=Path);p.add_argument('--directory',required=True,type=Path)
     14     p.add_argument('--candidate',type=Path,default=Path('/tmp/tricu-binding-compiler-first'))
     15     p.add_argument('--failed',type=Path,default=Path('/tmp/tricu-binding-compiler-measure'))
     16     args=p.parse_args();root=args.directory.resolve();root.mkdir(parents=True,exist_ok=False)
     17     workspace=root/'workspace';workspace.mkdir()
     18     previous=json.loads((args.failed/'report.json').read_text())
     19     for name,digest in previous['sources'].items():
     20         origin=args.failed/'workspace'/name;assert sha(origin)==digest
     21         (workspace/name).write_bytes(origin.read_bytes())
     22     candidate=json.loads((args.candidate/'report.json').read_text())
     23     assert sha(args.candidate/'candidate.arboricx')==candidate['candidate_sha256']
     24     runner=Runner(args.tricu,root,650,memory_mib=2048)
     25     report=dict(complete=False,harness_sha256=sha(Path(__file__)),prior_failure_report_sha256=sha(args.failed/'report.json'),
     26                 candidate_sha256=candidate['candidate_sha256'],runtime_sha256=sha(args.tricu),attempts=[])
     27     try:
     28         for role,bundle in [('candidate',args.candidate/'candidate.arboricx'),('accepted',ROOT/'bootstrap/build-stable.arboricx')]:
     29             pin=runner.imported(bundle,'import-'+role)
     30             store=root/(role+'-store');output=root/(role+'.arboricx')
     31             command=[str(args.tricu),'arboricx','compile','--file',str(workspace/'driver.tri'),
     32                      '--toolchain',pin,'--tool-store',str(runner.store),'--store',str(store),
     33                      '--output',str(output),'--compile-timeout','240','+RTS','-N1','-M2048m','-T','-s','-RTS']
     34             row=dict(role=role,command=command,samples=[]);report['attempts'].append(row)
     35             with (root/(role+'.log')).open('w') as log:
     36                 process=subprocess.Popen(command,stdout=log,stderr=subprocess.STDOUT,start_new_session=True)
     37                 start=time.monotonic();monitor=ChildRSS(process);last=-1
     38                 try:
     39                     while process.poll() is None:
     40                         rss=monitor.sample();elapsed=time.monotonic()-start
     41                         if rss is not None and rss>2048*1024:raise RuntimeError('RSS guard exceeded')
     42                         if int(elapsed)>last:
     43                             last=int(elapsed);cpu=None
     44                             if monitor.pid:
     45                                 try:
     46                                     fields=Path(f'/proc/{monitor.pid}/stat').read_text().rsplit(')',1)[1].split()
     47                                     cpu=(int(fields[11])+int(fields[12]))/os.sysconf('SC_CLK_TCK')
     48                                 except FileNotFoundError:pass
     49                             cache=store/'cache/source-build'
     50                             row['samples'].append(dict(seconds=elapsed,cpu_seconds=cpu,rss_kib=rss,
     51                                                        completed=sorted(x.name for x in cache.iterdir()) if cache.exists() else []))
     52                             (root/'progress.json').write_text(json.dumps(report,indent=2)+'\n')
     53                         if elapsed>270:raise RuntimeError('wall-time guard exceeded')
     54                         time.sleep(.05)
     55                     row['outcome']='complete' if process.returncode==0 else 'command-failed'
     56                 except RuntimeError as error:row['outcome']=str(error)
     57                 finally:
     58                     if process.poll() is None:
     59                         os.killpg(process.pid,signal.SIGTERM)
     60                         try:process.wait(timeout=10)
     61                         except subprocess.TimeoutExpired:os.killpg(process.pid,signal.SIGKILL);process.wait()
     62                     row['seconds']=time.monotonic()-start;row['returncode']=process.returncode
     63             row['rts']=parse_rts_stats((root/(role+'.log')).read_text())
     64             if output.exists():row['bundle_sha256']=sha(output)
     65             print(json.dumps({k:v for k,v in row.items() if k not in ['command','samples']}),flush=True)
     66         report['complete']=True
     67     finally:(root/'report.json').write_text(json.dumps(report,indent=2)+'\n')
     68 
     69 
     70 if __name__=='__main__':main()