forked from lijiext/lammps
236 lines
6.5 KiB
Python
Executable File
236 lines
6.5 KiB
Python
Executable File
#!/usr/bin/env python
|
|
"""
|
|
function: numerical comparisions of logs and corresponding benchmarks
|
|
usage: benchmark.py <nprocs> <njobs> <dirs>
|
|
"""
|
|
import sys
|
|
import os
|
|
import math
|
|
import re
|
|
from operator import itemgetter
|
|
from glob import glob
|
|
import time
|
|
import multiprocessing as mp
|
|
try:
|
|
import Queue as queue # 2.6
|
|
except ImportError:
|
|
import queue # 3.0
|
|
|
|
#====================================================
|
|
### constants
|
|
#====================================================
|
|
thermo_pattern = re.compile("^Step "); # fragile
|
|
data_pattern = re.compile("\s*\d"); # fragile
|
|
fail_pattern = re.compile("FAIL");
|
|
tol = 1.e-6 # 1.e-10
|
|
arch = "openmpi"
|
|
src_path = "../src/" #relative to home
|
|
exe_path = "../"+src_path
|
|
|
|
#====================================================
|
|
### date
|
|
#====================================================
|
|
def date():
|
|
return time.asctime()
|
|
|
|
#====================================================
|
|
### timer
|
|
#====================================================
|
|
## NOTE these don't seem to work how I expect them to
|
|
def start():
|
|
global dt
|
|
dt = -(time.clock())
|
|
def stop():
|
|
global dt
|
|
dt += (time.clock())
|
|
return dt
|
|
|
|
#====================================================
|
|
### run a benchmark
|
|
#====================================================
|
|
def run_test(test):
|
|
input = "in."+test;
|
|
log = "log."+test
|
|
stdout = "stdout."+test
|
|
ref = (glob(log+"*."+str(np)))[0];
|
|
msg = "==== comparing "+log+" with "+ref+" ====\n"
|
|
if (os.path.isfile(log)): os.remove(log)
|
|
if (os.path.isfile(stdout)): os.remove(stdout)
|
|
os.system(lmps+input+" >& "+stdout);
|
|
if (not os.path.isfile(log)) :
|
|
msg += "!!! no "+log+"\n";
|
|
msg += "!!! test "+test+" FAILED\n"
|
|
return msg
|
|
[cdict,cdata] = extract_data(log);
|
|
[bdict,bdata] = extract_data(ref);
|
|
cols = range(len(bdict))
|
|
if (len(cdata) != len(bdata)):
|
|
msg += "!!! data size "+str(len(cdata))+" does not match data "+str(len(bdata))+" in "+ref+"\n";
|
|
msg += "!!! test "+test+" FAILED\n"
|
|
return msg
|
|
fail = False
|
|
i = 0
|
|
for name in bdict:
|
|
[passing,cmsg] = compare(name,cdata[cols[i]],bdata[cols[i]]);
|
|
i += 1
|
|
msg += cmsg
|
|
if (not passing) : fail = True
|
|
if (fail) :
|
|
msg += "!!! test "+test+" FAILED\n"
|
|
else :
|
|
msg += "*** test "+test+" passed\n"
|
|
return msg
|
|
|
|
#====================================================
|
|
### extract data from log file
|
|
#====================================================
|
|
def extract_data(file):
|
|
dictionary = [];
|
|
data = []
|
|
read = False
|
|
for line in open(file):
|
|
if (read and data_pattern.match(line)) :
|
|
cols = line.split();
|
|
data.append(cols)
|
|
else :
|
|
read = False
|
|
if (thermo_pattern.match(line)):
|
|
dictionary = line.split();
|
|
read = True
|
|
return [dictionary,data]
|
|
|
|
#====================================================
|
|
### compare columns of current and benchmark
|
|
#====================================================
|
|
def compare(name,col1,col2):
|
|
err = 0.
|
|
norm1 = 0.
|
|
norm2 = 0.
|
|
n = len(col2)
|
|
for i in range(n):
|
|
v1 = float(col1[i])
|
|
v2 = float(col2[i])
|
|
norm1 += v1*v1
|
|
norm2 += v2*v2
|
|
dv = v1-v2
|
|
err += dv*dv
|
|
norm1 /= n
|
|
norm2 /= n
|
|
err /= n
|
|
if (norm2 > tol) :
|
|
msg = "{0:7s} relative error {1:4} wrt norm {2:7}\n".format(name,err,norm2)
|
|
else :
|
|
msg = "{0:7s} error {1:4}\n" .format(name,err)
|
|
return [(err < tol),msg];
|
|
|
|
#################################################################
|
|
class Worker(mp.Process):
|
|
def __init__(self, work_queue, result_queue):
|
|
mp.Process.__init__(self)
|
|
self.work_queue = work_queue
|
|
self.result_queue = result_queue
|
|
def run(self):
|
|
while True:
|
|
try:
|
|
job = self.work_queue.get_nowait()
|
|
except queue.Empty:
|
|
break
|
|
#print(">>> starting " + str(job[1]) + " ...")
|
|
os.chdir(job[0])
|
|
start()
|
|
msg = run_test(job[1])
|
|
elapsed_time = stop()
|
|
msg += "elapsed time "+str(elapsed_time)+"\n"
|
|
os.chdir(home)
|
|
self.result_queue.put([job[1],msg])
|
|
|
|
#====================================================
|
|
### parse
|
|
#====================================================
|
|
def init() :
|
|
global np, njobs, ntests, lmps, arch, home
|
|
home = os.getcwd()
|
|
if (len(sys.argv) < 4) :
|
|
print "usage: benchmark.py <nprocs> <njobs> <test_dirs>"
|
|
sys.exit(1)
|
|
np = int(sys.argv[1])
|
|
njobs = int(sys.argv[2])
|
|
lmps = "../"+src_path+"lmp_"+arch+" -in "
|
|
if (np > 1):
|
|
lmps = "mpirun -np "+str(np)+" "+lmps
|
|
else:
|
|
arch = "serial"
|
|
lmps = exe_path+"lmp_"+arch+" -in "
|
|
pool = mp.Pool(njobs)
|
|
dirs = sys.argv[3:]
|
|
tests = []
|
|
for dir in dirs:
|
|
os.chdir(dir);
|
|
for path in glob("./in.*"):
|
|
test = path[5:];
|
|
tests.append([dir,test])
|
|
os.chdir(home)
|
|
ntests = len(tests)
|
|
print "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
|
|
print "start: ",date()
|
|
print "arch:",arch,
|
|
print "nprocs:",np
|
|
print "ntests:",ntests,
|
|
print "njobs:",njobs
|
|
print "relative tolerance:",tol
|
|
print "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
|
|
print
|
|
return tests
|
|
|
|
#====================================================
|
|
### build executable
|
|
#====================================================
|
|
def build(arch):
|
|
os.system("cd ..; svn update >& svn_update.log")
|
|
os.system("cd ../src; make no-atc >& /dev/null")
|
|
os.system("cd ../src; make clean-all >& /dev/null")
|
|
#os.system("cd ../src; make yes-all >& /dev/null")
|
|
os.system("cd ../src; make yes-dipole >& /dev/null")
|
|
sys.stdout.flush()
|
|
print "** building ",arch,"...",
|
|
os.system("cd "+src_path+"; make -j "+str(np)+" "+arch+" >& build_"+arch+".log")
|
|
if (not os.path.isfile(src_path+"lmp_"+arch)) :
|
|
print "!!! build ",arch," FAILED"
|
|
sys.exit()
|
|
else:
|
|
print "done"
|
|
print
|
|
|
|
#====================================================
|
|
### main
|
|
#====================================================
|
|
if __name__ == '__main__':
|
|
tests = init()
|
|
build(arch)
|
|
work_queue = mp.Queue()
|
|
for test in tests:
|
|
work_queue.put(test)
|
|
result_queue = mp.Queue()
|
|
nfails = 0
|
|
fail_list = []
|
|
for i in range(njobs):
|
|
w = Worker(work_queue, result_queue)
|
|
w.start()
|
|
for i in range(ntests):
|
|
[test,msg] = result_queue.get()
|
|
if (fail_pattern.search(msg)) :
|
|
nfails += 1
|
|
fail_list.append(test)
|
|
#print msg # can print only if failed
|
|
print msg # can print only if failed
|
|
#print test, " passed"
|
|
print "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
|
|
print "end:",date()
|
|
if (nfails == 0):
|
|
print "*** no failures ***"
|
|
else :
|
|
print "!!!",nfails,"of",ntests,"tests failed"
|
|
for test in fail_list:
|
|
print test
|
|
print "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
|