binding_failure_isolate.py (4299B)
1 #!/usr/bin/env python3 2 """Bounded prefix isolation of the unpublished compiler's pipelines stall.""" 3 import argparse,json,re,time 4 from pathlib import Path 5 from float_multiply import Runner,sha 6 from binding_substitution import ROOT 7 from bundle_dag import read,Intern 8 9 10 def main(): 11 p=argparse.ArgumentParser(description=__doc__) 12 p.add_argument('tricu',type=Path);p.add_argument('--directory',type=Path,required=True) 13 p.add_argument('--candidate',type=Path,default=Path('/tmp/tricu-binding-compiler-first')) 14 p.add_argument('--failed',type=Path,default=Path('/tmp/tricu-binding-compiler-measure')) 15 args=p.parse_args();root=args.directory.resolve();root.mkdir(parents=True,exist_ok=False) 16 workspace=root/'workspace';workspace.mkdir();runner=Runner(args.tricu,root,600,memory_mib=2048) 17 prior=json.loads((args.candidate/'report.json').read_text());assert prior['complete'] 18 assert sha(args.candidate/'candidate.arboricx')==prior['candidate_sha256'] 19 report=dict(complete=False,harness_sha256=sha(Path(__file__)),candidate_sha256=prior['candidate_sha256'], 20 runtime_sha256=sha(args.tricu),dependencies=[],attempts=[]) 21 try: 22 tools={role:runner.imported(path,role) for role,path in [('accepted',ROOT/'bootstrap/build-stable.arboricx'),('candidate',args.candidate/'candidate.arboricx')]} 23 for alias in ['native_math','kernels','layouts']: 24 graphs={};intern=Intern() 25 for role in tools: 26 store=args.failed/f'compile-0-{role}-store' 27 manifest=(store/'cache/source-build'/alias).read_text().split('\t')[2] 28 bundle=root/(role+'-'+alias+'.arboricx') 29 runner.run('export-'+role+alias,['export','--store',store,'--module',manifest,'--output',bundle]) 30 _,_,nodes,exports,_=read(bundle);ids=intern.graph(nodes) 31 graphs[role]={name:ids[i] for name,i in exports.items()} 32 different=[name for name in graphs['accepted'] if graphs['accepted'][name]!=graphs['candidate'][name]] 33 report['dependencies'].append(dict(alias=alias,changed_exports=different)) 34 pin=runner.imported(root/('accepted-'+alias+'.arboricx'),'dep-'+alias) 35 (workspace/(alias+'.tri')).write_text('!export * from '+pin+'\n') 36 source=(args.failed/'workspace/pipelines.tri').read_text() 37 positions=[m.start() for m in re.finditer(r'^[A-Za-z][A-Za-z0-9_]*[^\n]*=',source,re.M)] 38 names=[re.match(r'[A-Za-z][A-Za-z0-9_]*',source[pos:])[0] for pos in positions] 39 report['definitions']=names 40 def attempt(count,role): 41 text=source[:positions[count]] if count<len(positions) else source 42 (workspace/'probe.tri').write_text(text) 43 label=f'{role}-{count}';start=time.monotonic() 44 try: 45 runner.run(label,['compile','--file',workspace/'probe.tri','--toolchain',tools[role], 46 '--tool-store',runner.store,'--store',runner.store,'--output',root/(label+'.arboricx'), 47 '--compile-timeout','45'],55) 48 row=dict(role=role,count=count,last=names[count-1],outcome='complete',seconds=time.monotonic()-start, 49 rts=runner.records[-1]['rts_process']) 50 except RuntimeError as error: 51 if str(error)!='wall-time guard exceeded':raise 52 row=dict(role=role,count=count,last=names[count-1],outcome='timeout',seconds=time.monotonic()-start) 53 report['attempts'].append(row);print(json.dumps(row),flush=True) 54 return row['outcome']=='complete' 55 assert attempt(len(names),'accepted') 56 if attempt(len(names),'candidate'): 57 report['complete']=True;report['reproduced']=False;return 58 lo,hi=0,len(names) 59 while hi-lo>1: 60 mid=(lo+hi)//2 61 if attempt(mid,'candidate'):lo=mid 62 else:hi=mid 63 report['boundary']=dict(completed_prefix=lo,first_timeout_prefix=hi,definition=names[hi-1]) 64 # Verify this boundary against accepted lowering too. 65 assert attempt(hi,'accepted') 66 report['complete']=True;report['reproduced']=True 67 finally:(root/'report.json').write_text(json.dumps(report,indent=2)+'\n') 68 69 70 if __name__=='__main__':main()