-rwxr-xr-x 12493 djbsort-20190516/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')