-rwxr-xr-x 12493 djbsort-20180729/test
#!/usr/bin/env python3 import string import re import platform import sys import os import signal import subprocess import shutil import datetime def readfile(fn): with open(fn,'r') as f: return f.read() def writefilebinary(fn,s): with open(fn,'wb') as f: f.write(s) def writefile(fn,s): with open(fn,'w') as f: f.write(s) def copymkdir(old,dir): try: os.makedirs(dir) except: pass shutil.copy(old,dir) project = 'djbsort' version = readfile('version').strip() shorthostname = platform.node().split('.')[0].lower() okcharacters = string.ascii_letters + string.digits shorthostname = ''.join(c for c in shorthostname if c in okcharacters) startdir = os.getcwd() compiled = '%s/link-build/obj-%s/%s' % (startdir,version,shorthostname) work = '%s/link-build/test-%s/%s' % (startdir,version,shorthostname) shutil.rmtree(work,True) os.makedirs(work) notes = '%s/notes' % work os.makedirs(notes) log = open('%s/log' % notes,'w') tmp = '%s/tmp' % work objproject = '%s/obj' % work shutil.rmtree(objproject,True) os.makedirs(objproject) testlib = '%s/lib' % work shutil.rmtree(testlib,True) os.makedirs(testlib) installlib = '%s/link-install/run-%s/%s/lib' % (startdir,version,shorthostname) shutil.rmtree(installlib,True) os.makedirs(installlib) rpath = os.path.realpath(installlib) command = '%s/link-install/run-%s/%s/command' % (startdir,version,shorthostname) shutil.rmtree(command,True) os.makedirs(command) logprevious = None def lognow(x,y=''): global logprevious x = re.sub('\n','_',x) output = '%s\n' % x if y: try: y = y.decode() except: pass for z in y.splitlines(): output += '> %s\n' % z now = datetime.datetime.now() if logprevious == None: logprevious = now duration = (now - logprevious).total_seconds() logprevious = now log.write('%s === %9f === %s' % (now.ctime(),duration,output)) log.flush() sys.stdout.write(output) sys.stdout.flush() lognow('test starting') lognow('version %s' % version) lognow('hostname %s' % shorthostname) signals = dict((getattr(signal,x),x) for x in dir(signal) if x.startswith('SIG') and '_' not in x) def returncodestr(n): if -n in signals: return signals[-n] return str(n) def addlibproject(abi,fo,membername): staticlib = '%s/%s/lib%s.a' % (installlib,abi,project) doto = '%s/%s/%s' % (objproject,abi,membername) if os.path.exists(doto): lognow('error: overwriting %s' % membername) return shutil.copy(fo,doto) try: cmd = 'ar cr %s %s' % (staticlib,doto) p = subprocess.Popen(cmd.split(),stdout=subprocess.PIPE,stderr=subprocess.STDOUT) out,err = p.communicate() if out: lognow('archiver stdout',out) if err: lognow('archiver stderr',err) if p.returncode: lognow('archiver failed exit %s' % returncodestr(p.returncode)) except Exception as e: lognow('archiver failed %s' % e) try: cmd = 'ranlib %s' % staticlib p = subprocess.Popen(cmd.split(),stdout=subprocess.PIPE,stderr=subprocess.STDOUT) out,err = p.communicate() if out: lognow('ranlib stdout',out) if err: lognow('ranlib stderr',err) if p.returncode: lognow('ranlib failed exit %s' % returncodestr(p.returncode)) except Exception as e: lognow('ranlib failed %s' % e) def link(c,c_,tmp,dir,exe,o): try: cmd = '%s -fvisibility=hidden -o %s %s' % (c,exe,' '.join(o)) p = subprocess.Popen(cmd.split(),cwd=tmp,stdout=subprocess.PIPE,stderr=subprocess.STDOUT) out,err = p.communicate() assert not err if out: lognow('linker output',out) try: os.makedirs('%s/%s/%s' % (notes,c_,dir)) except: pass writefilebinary('%s/%s/%s/%s' % (notes,c_,dir,exe),out) if p.returncode: lognow('%s/%s linker failed %s' % (dir,exe,returncodestr(p.returncode))) return False return True except Exception as e: lognow('%s/%s linker exited %s' % (dir,exe,e)) return False def run(c,c_,tmp,dir,exe): try: cmd = './%s' % exe p = subprocess.Popen(cmd.split(),cwd=tmp,stdout=subprocess.PIPE,stderr=subprocess.PIPE) out,err = p.communicate() if err: lognow('test stderr',err) try: os.makedirs('%s/%s/%s' % (notes,c_,dir)) except: pass writefilebinary('%s/%s/%s/%s' % (notes,c_,dir,exe),err) if p.returncode: lognow('%s/%s test exited %s' % (dir,exe,returncodestr(p.returncode))) return return out.decode() except Exception as e: lognow('%s/%s test failed %s' % (dir,exe,e)) return # ----- abi and syslibs compilers = {} compilers['c'] = readfile('compilers/c').splitlines() compilerabi = {} abis = [] syslibs = {} for c in compilers['c']: c = c.strip() if c == '': continue c_ = re.sub(' ','_',c) compilerabi[c] = c_ syslibs[c] = [] shutil.rmtree(tmp,True) dir = '%s/%s/compilers' % (compiled,c_) if not os.path.exists(dir): continue shutil.copytree(dir,tmp) if link(c,c_,tmp,'compilers','abiname',['abiname.o']): abi = run(c,c_,tmp,'compilers','abiname') if abi: abi = abi.strip() compilerabi[c] = abi try: os.makedirs('%s/%s' % (objproject,abi)) os.makedirs('%s/%s' % (testlib,abi)) os.makedirs('%s/%s' % (installlib,abi)) addlibproject(abi,'%s/base.o' % tmp,'base.o') os.symlink('../../include','%s/%s/include' % (installlib,abi)) os.symlink(abi,'%s/0' % installlib) except: pass lognow('abi %s %s %s' % (compilerabi[c],c,' '.join(syslibs[c]))) if not compilerabi[c] in abis: abis += [compilerabi[c]] # XXX: check compatibility of compilers with same alleged abi # ----- cpucycles abicounter = {} for counter in sorted(os.listdir('cpucycles')): if not os.path.isdir('cpucycles/%s' % counter): continue for c in compilers['c']: c = c.strip() if c == '': continue c_ = re.sub(' ','_',c) dir = '%s/%s/cpucycles/%s' % (compiled,c_,counter) if not os.path.exists(dir): continue if os.path.exists('%s/architectures' % dir): if all(dirabi.strip() != compilerabi[c] for dirabi in readfile('%s/architectures' % dir).splitlines()): lognow('cpucycles/%s skipping architecture %s' % (counter,c)) continue abi = compilerabi[c] lognow('cpucycles/%s testing %s' % (counter,c)) shutil.rmtree(tmp,True) shutil.copytree(dir,tmp) if link(c,c_,tmp,'cpucycles/%s' % counter,'test',['test.o','cpucycles.o','implementation.o']): cycles = run(c,c_,tmp,'cpucycles/%s' % counter,'test') if cycles: cycles = int(cycles.strip()) lognow('cpucycles/%s cycles %s %s' % (counter,cycles,c)) if abi not in abicounter or cycles < abicounter[abi][0]: abicounter[abi] = (cycles,counter,c) for abi in abis: if abi not in abicounter: raise Exception('no working cycle counter for %s' % abi) cycles,counter,c = abicounter[abi] lognow('selected %s cpucycles/%s %s %s' % (abi,counter,cycles,c)) c_ = re.sub(' ','_',c) dir = '%s/%s/cpucycles/%s' % (compiled,c_,counter) addlibproject(abi,'%s/cpucycles.o' % dir,'cpucycles.o') addlibproject(abi,'%s/implementation.o' % dir,'cpucycles_implementation.o') # ----- sorting types = readfile('TYPES').splitlines() for t in types: t = t.strip() if t == '': continue if not os.path.isdir(t): continue o = '%s_sort' % t cyclesimpl = {} for impl in sorted(os.listdir(t)): implementationdir = '%s/%s' % (t,impl) if not os.path.isdir(implementationdir): continue opi = 'djbsort_%s_impl' % t files = sorted(os.listdir(implementationdir)) cfiles = [x for x in files if x.endswith('.c')] sfiles = [x for x in files if x.endswith('.s') or x.endswith('.S')] files = cfiles + sfiles if 'compiler.c' not in files: files += ['compiler.c'] if 'version.c' not in files: files += ['version.c'] if 'implementation.c' not in files: files += ['implementation.c'] files = ['%s.o' % x[:-2] for x in files] ok = True for f in files: if f[0] == '-': lognow('%s skipping because of invalid filename %s' % (implementationdir,f)) ok = False for c in f: if c not in string.ascii_letters + string.digits + '._-': lognow('%s skipping because of invalid filename %s' % (implementationdir,f)) ok = False if not ok: continue for c in compilers['c']: c = c.strip() if c == '': continue c_ = re.sub(' ','_',c) abi = compilerabi[c] dir = '%s/%s/%s' % (compiled,c_,implementationdir) if not os.path.isdir(dir): continue if os.path.exists('%s/architectures' % dir): if all(dirabi.strip() != abi for dirabi in readfile('%s/architectures' % dir).splitlines()): lognow('%s skipping architecture %s' % (implementationdir,c)) continue shutil.rmtree(tmp,True) shutil.copytree(dir,tmp) copt = c copt += ' -L%s/%s' % (installlib,abi) libs = [] libs += ['-l%s' % project] libs += syslibs[c] trylibs = libs lognow('%s/cycles testing %s' % (implementationdir,c)) # see whether files are PIC-compatible if not link(copt + ' -shared',c_,tmp,implementationdir,'shared.so',files): continue # use files rather than shared.so to be able to access hidden symbols if not link(copt,c_,tmp,implementationdir,'cycles',['cycles.o'] + files + trylibs): continue cycles = run(copt,c_,tmp,implementationdir,'cycles') try: cycles = int(cycles) if not abi in cyclesimpl: cyclesimpl[abi] = [] cyclesimpl[abi] += [(cycles,implementationdir,c,files,copt,libs,trylibs)] lognow('%s cycles %d %s' % (implementationdir,cycles,c)) except: continue for abi in abis: if not abi in cyclesimpl: cyclesimpl[abi] = [] cyclesimpl[abi].sort() ok = False for cycles,implementationdir,c,files,copt,libs,trylibs in cyclesimpl[abi]: c_ = re.sub(' ','_',c) shutil.rmtree(tmp,True) shutil.copytree('%s/%s/%s' % (compiled,c_,implementationdir),tmp) lognow('%s/works testing %s' % (implementationdir,c)) if not link(copt,c_,tmp,implementationdir,'works',['works.o'] + files + trylibs): continue out = run(copt,c_,tmp,implementationdir,'works') if out == None: continue lognow('selected %s %s %s %s' % (abi,implementationdir,cycles,c)) c_ = re.sub(' ','_',c) for f in files: addlibproject(abi,'%s/%s' % (tmp,f),re.sub('/','_','%s_%s' % (implementationdir,f))) writefile('%s/%s/compiler' % (installlib,abi),c + '\n') ok = True break if not ok: lognow('selectfails %s %s no working implementation' % (abi,o)) # ----- shared library abishared = set() for c in compilers['c']: c = c.strip() if c == '': continue c_ = re.sub(' ','_',c) abi = compilerabi[c] if abi in abishared: continue if not os.path.exists('%s/%s' % (objproject,abi)): continue shutil.rmtree(tmp,True) shutil.copytree('%s/%s' % (objproject,abi),tmp) copt = c copt += ' -shared' copt += ' -Wl,-soname,lib%s.so.1' % project if link(copt,c_,tmp,'shared','lib%s.so.1' % project,sorted(os.listdir(tmp)) + syslibs[c]): shutil.copy('%s/lib%s.so.1' % (tmp,project),'%s/%s/' % (installlib,abi)) os.symlink('lib%s.so.1' % project,'%s/%s/lib%s.so' % (installlib,abi,project)) abishared.add(abi) # ----- command for t in types: t = t.strip() if t == '': continue if not os.path.isdir(t): continue cmd = '%s-speed' % t for c in compilers['c']: c = c.strip() if c == '': continue c_ = re.sub(' ','_',c) abi = compilerabi[c] dir = '%s/%s/%s' % (compiled,c_,'command') if not os.path.exists('%s/%s.o' % (dir,cmd)): continue if not os.path.exists('%s/limits.o' % dir): continue lognow('command/%s linking %s' % (cmd,c)) copt = c copt += ' -L%s/%s' % (installlib,abi) copt += ' -Wl,-rpath=%s/%s' % (rpath,abi) libs = [] libs += ['-l%s' % project] libs += syslibs[c] shutil.rmtree(tmp,True) os.mkdir(tmp) shutil.copy('%s/%s.o' % (dir,cmd),tmp) shutil.copy('%s/limits.o' % dir,tmp) if link(copt,c_,tmp,'command',cmd,['%s.o' % cmd,'limits.o'] + libs): copymkdir('%s/%s' % (tmp,cmd),command) os.chmod('%s/%s' % (command,cmd),0o711) break # ----- finishing shutil.rmtree(tmp,True) lognow('test finishing successfully')