#!/usr/bin/env python3 """Logged, serial, bounded command runner. A timeout stops this invocation.""" import hashlib import fcntl import os from pathlib import Path import shlex import signal import subprocess import sys import time root = Path(__file__).resolve().parents[2] def run(name, command, seconds=45): guard=open('/tmp/gr_psf_replay.lock','w') fcntl.flock(guard,fcntl.LOCK_EX|fcntl.LOCK_NB) running=subprocess.check_output(['ps','-eo','pid=,comm='],text=True) names={'replay_psf','capture_psf','benchmark_hip_p','test_hip_psf','minkowski_sky','minkowski_sky_h','schwarzschild_s'} conflicts=[line for line in running.splitlines() if line.split()[-1] in names] if conflicts:raise RuntimeError('another test/render is running: '+str(conflicts)) logfile = Path(__file__).parent / (name + '.log') if logfile.exists(): raise RuntimeError(f'refusing to overwrite {logfile}') env = dict(os.environ, OMP_NUM_THREADS='16', OMP_DYNAMIC='FALSE') with logfile.open('x') as out: out.write('COMMAND OMP_NUM_THREADS=16 OMP_DYNAMIC=FALSE ' + shlex.join(command) + '\n') out.write(f'TIMEOUT {seconds}s\n') out.write('GIT ' + subprocess.check_output(['git','rev-parse','HEAD'],cwd=root,text=True)) binary_index = 0 if command[0] == 'env': binary_index = 1 while binary_index < len(command) and '=' in command[binary_index]: binary_index += 1 binary = Path(command[binary_index]) if binary_index < len(command) else Path() if binary.is_file(): out.write('BINARY_SHA256 ' + hashlib.sha256(binary.read_bytes()).hexdigest() + '\n') out.flush() start = time.monotonic() p = subprocess.Popen(command,cwd=root,env=env,stdout=out,stderr=subprocess.STDOUT,start_new_session=True) try: status = p.wait(timeout=seconds) except subprocess.TimeoutExpired: os.killpg(p.pid, signal.SIGKILL) p.wait() out.write(f'TIMEOUT killed and reaped pid={p.pid}\n') raise out.write(f'PROCESS_WALL {time.monotonic()-start:.9f} EXIT {status}\n') print(f"{name}: exit={status}; raw output: {logfile}", flush=True) if status: raise RuntimeError(f'{name} exit {status}; stop and inspect') if __name__ == '__main__': run(sys.argv[1], sys.argv[3:], int(sys.argv[2]))