contrib/intel/jenkins/tests.py (394 lines of code) (raw):
import sys
import os
print(os.environ['CI_SITE_CONFIG'])
sys.path.append(os.environ['CI_SITE_CONFIG']) # for adding path for ci_site_config
import subprocess
import re
import ci_site_config
import common
import shlex
from abc import ABC, abstractmethod # abstract base class for creating abstract classes in python
# A Jenkins env variable for job name is composed of the name of the jenkins job and the branch name
# it is building for. for e.g. in our case jobname = 'ofi_libfabric/master'
class Test:
def __init__ (self, jobname, buildno, testname, core_prov, fabric,
hosts, ofi_build_mode, util_prov=None):
self.jobname = jobname
self.buildno = buildno
self.testname = testname
self.core_prov = core_prov
self.util_prov = "ofi_{}".format(util_prov) if util_prov != None else ""
self.fabric = fabric
self.hosts = hosts
self.ofi_build_mode = ofi_build_mode
if (len(hosts) == 2):
self.server = hosts[0]
self.client = hosts[1]
self.nw_interface = ci_site_config.interface_map[self.fabric]
self.libfab_installpath = "{}/{}/{}/{}".format(ci_site_config.install_dir,
self.jobname, self.buildno, self.ofi_build_mode)
self.env = [("FI_VERBS_MR_CACHE_ENABLE", "1"),\
("FI_VERBS_INLINE_SIZE", "256")] \
if self.core_prov == "verbs" else []
class FiInfoTest(Test):
def __init__(self, jobname, buildno, testname, core_prov, fabric,
hosts, ofi_build_mode, util_prov=None):
super().__init__(jobname, buildno, testname, core_prov, fabric,
hosts, ofi_build_mode, util_prov)
self.fi_info_testpath = "{}/bin".format(self.libfab_installpath)
@property
def cmd(self):
return "{}/fi_info ".format(self.fi_info_testpath)
@property
def options(self):
if (self.util_prov):
opts = "-f -p {};{}".format(self.core_prov, self.util_prov)
else:
opts = "-f -p {}".format(self.core_prov)
return opts
def execute_cmd(self):
command = self.cmd + self.options
outputcmd = shlex.split(command)
common.run_command(outputcmd)
class Fabtest(Test):
def __init__(self, jobname, buildno, testname, core_prov, fabric,
hosts, ofi_build_mode, util_prov=None):
super().__init__(jobname, buildno, testname, core_prov, fabric,
hosts, ofi_build_mode, util_prov)
self.fabtestpath = "{}/bin".format(self.libfab_installpath)
self.fabtestconfigpath = "{}/share/fabtests".format(self.libfab_installpath)
def get_exclude_file(self):
path = self.libfab_installpath
efile_path = "{}/share/fabtests/test_configs".format(path)
prov = self.util_prov if self.util_prov else self.core_prov
efile_old = "{path}/{prov}/{prov}.exclude".format(path=efile_path,
prov=prov)
if self.util_prov:
efile = "{path}/{util_prov}/{core_prov}/exclude".format(path=efile_path,
util_prov=self.util_prov, core_prov=self.core_prov)
else:
efile = "{path}/{prov}/exclude".format(path=efile_path,
prov=self.core_prov)
if os.path.isfile(efile):
return efile
elif os.path.isfile(efile_old):
return efile_old
else:
print("Exclude file: {} not found!".format(efile))
return None
@property
def cmd(self):
return "{}/runfabtests.sh ".format(self.fabtestpath)
@property
def options(self):
opts = "-T 300 -vvv -p {} -S ".format(self.fabtestpath)
if (self.core_prov == "verbs" and self.nw_interface):
opts = "{} -s {} ".format(opts, common.get_node_name(self.server,
self.nw_interface)) # include common.py
opts = "{} -c {} ".format(opts, common.get_node_name(self.client,
self.nw_interface)) # from common.py
if (self.core_prov == "shm"):
opts = "{} -s {} ".format(opts, self.server)
opts = "{} -c {} ".format(opts, self.client)
opts += "-N "
if not re.match(".*sockets|udp|tcp.*", self.core_prov):
opts = "{} -t all ".format(opts)
efile = self.get_exclude_file()
if efile:
opts = "{} -R ".format(opts)
opts = "{} -f {} ".format(opts, efile)
for key,val in self.env:
opts = "{options} -E {key}={value} ".format(options = opts,
key=key, value=val)
if self.util_prov:
opts = "{options} {core};{util} ".format(options=opts,
core=self.core_prov, util=self.util_prov)
else:
opts = "{options} {core} ".format(options=opts,
core=self.core_prov)
if (self.core_prov == "shm"):
opts += "{} {} ".format(self.server, self.server)
else:
opts += "{} {} ".format(self.server, self.client)
return opts
@property
def execute_condn(self):
# fabtests works for shmem prov only for libfabric debug builds.
return True if (self.core_prov != 'shm' or \
self.ofi_build_mode == 'dbg') else False
def execute_cmd(self):
curdir = os.getcwd()
os.chdir(self.fabtestconfigpath)
command = self.cmd + self.options
outputcmd = shlex.split(command)
common.run_command(outputcmd)
os.chdir(curdir)
class ShmemTest(Test):
def __init__(self, jobname, buildno, testname, core_prov, fabric,
hosts, ofi_build_mode, util_prov=None):
super().__init__(jobname, buildno, testname, core_prov, fabric,
hosts, ofi_build_mode, util_prov)
#self.n - number of hosts * number of processes per host
self.n = 4
# self.ppn - number of processes per node.
self.ppn = 2
self.shmem_dir = "{}/shmem".format(self.libfab_installpath)
@property
def cmd(self):
#todo: rename mpi_testpath to testpath to make it generic for shmem and mpitest
return "{}/run_shmem.sh ".format(ci_site_config.mpi_testpath)
def options(self, shmem_testname):
if self.util_prov:
prov = "{core};{util} ".format(core=self.core_prov,
util=self.util_prov)
else:
prov = self.core_prov
opts = "-n {n} -hosts {server},{client} -shmem_dir={shmemdir} \
-libfabric_path={path}/lib -prov '{provider}' -test {test} \
-server {server} -inf {inf}" \
.format(n=self.n, server=self.server, client=self.client, \
shmemdir=self.shmem_dir, path=self.libfab_installpath, \
provider=prov, test=shmem_testname, \
inf=ci_site_config.interface_map[self.fabric])
return opts
@property
def execute_condn(self):
return True if (self.core_prov == "psm2" or self.core_prov == "sockets") \
else False
def execute_cmd(self, shmem_testname):
command = self.cmd + self.options(shmem_testname)
outputcmd = shlex.split(command)
common.run_command(outputcmd)
class MpiTests(Test):
def __init__(self, jobname, buildno, testname, core_prov, fabric,
mpitype, hosts, ofi_build_mode, util_prov=None):
super().__init__(jobname, buildno, testname, core_prov,
fabric, hosts, ofi_build_mode, util_prov)
self.mpi = mpitype
@property
def cmd(self):
if (self.mpi == "impi" or self.mpi == "mpich"):
self.testpath = ci_site_config.mpi_testpath
return "{}/run_{}.sh ".format(self.testpath,self.mpi)
elif(self.mpi =="ompi"):
self.testpath = "{}/ompi/bin".format(self.libfab_installpath)
return "{}/mpirun ".format(self.testpath)
@property
def options(self):
opts = []
if (self.mpi == "impi" or self.mpi == "mpich"):
opts = "-n {} -ppn {} -hosts {},{} ".format(self.n,self.ppn,
self.server,self.client)
if (self.mpi == "impi"):
opts = "{} -mpi_root={} ".format(opts,
ci_site_config.impi_root)
else:
opts = "{} -mpi_root={}/mpich".format(opts,
self.libfab_installpath)
opts = "{} -libfabric_path={}/lib ".format(opts,
self.libfab_installpath)
if self.util_prov:
opts = "{options} -prov {core};{util} ".format(options=opts,
core=self.core_prov, util=self.util_prov)
else:
opts = "{} -prov {} ".format(opts, self.core_prov)
for key, val in self.env:
opts = "{} -genv {} {} ".format(opts, key, val)
elif (self.mpi == "ompi"):
opts = "-np {} ".format(self.n)
hosts = ",".join([":".join([host,str(self.ppn)]) \
for host in self.hosts])
opts = "{} --host {} ".format(opts, hosts)
if self.util_prov:
opts = "{} --mca mtl_ofi_provider_include {};{} ".format(opts,
self.core_prov,self.util_prov)
else:
opts = "{} --mca mtl_ofi_provider_include {} ".format(opts,
self.core_prov)
opts += "--mca orte_base_help_aggregate 0 "
opts += "--mca mtl ofi --mca pml cm -tag-output "
for key,val in self.env:
opts = "{} -x {}={} ".format(opts,key,val)
return opts
@property
def mpi_gen_execute_condn(self):
#Skip MPI tests for udp, verbs(core) providers.
# we would still have MPI tests runnning for
# verbs-rxd and verbs-rxm providers
return True if (self.core_prov != "udp" and \
self.core_prov != "shm" and \
(self.core_prov != "verbs" or \
self.util_prov == "ofi_rxm" or \
self.util_prov == "ofi_rxd")) else False
# IMBtests serves as an abstract class for different
# types of intel MPI benchmarks. Currently we have
# the mpi1 and rma tests enabled which are encapsulated
# in the IMB_mpi1 and IMB_rma classes below.
class IMBtests(ABC):
"""
This is an abstract class for IMB tests.
currently IMB-MPI1 and IMB-RMA tests are
supported. In future there could be more.
All abstract methods must be implemented.
"""
@property
@abstractmethod
def imb_cmd(self):
pass
@property
@abstractmethod
def execute_condn(self):
pass
class IMBmpi1(IMBtests):
def __init__(self):
self.additional_tests = [
"Biband",
"Uniband",
"PingPongAnySource",
"PingPingAnySource",
"PingPongSpecificSource",
"PingPingSpecificSource"
]
@property
def imb_cmd(self):
return "{}/intel64/bin/IMB-MPI1 -include {}".format(ci_site_config.impi_root, \
','.join(self.additional_tests))
@property
def execute_condn(self):
return True
class IMBrma(IMBtests):
def __init__(self, core_prov):
self.core_prov = core_prov
@property
def imb_cmd(self):
return "{}/intel64/bin/IMB-RMA".format(ci_site_config.impi_root)
@property
def execute_condn(self):
return True if (self.core_prov != "verbs") else False
# MpiTestIMB class inherits from the MPITests class.
# It uses the same options method and class variables as all MPI tests.
# It creates IMB_xxx test objects for each kind of IMB test.
class MpiTestIMB(MpiTests):
def __init__(self, jobname, buildno, testname, core_prov, fabric,
mpitype, hosts, ofi_build_mode, util_prov=None):
super().__init__(jobname, buildno, testname, core_prov, fabric,
mpitype, hosts, ofi_build_mode, util_prov)
self.n = 4
self.ppn = 1
self.mpi1 = IMBmpi1()
self.rma = IMBrma(self.core_prov)
@property
def execute_condn(self):
return True if (self.mpi == "impi") else False
def execute_cmd(self):
command = self.cmd + self.options
if(self.mpi1.execute_condn):
outputcmd = shlex.split(command + self.mpi1.imb_cmd)
common.run_command(outputcmd)
if (self.rma.execute_condn):
outputcmd = shlex.split(command + self.rma.imb_cmd)
common.run_command(outputcmd)
class MpichTestSuite(MpiTests):
def __init__(self, jobname, buildno, testname, core_prov, fabric,
mpitype, hosts, ofi_build_mode, util_prov=None):
super().__init__(jobname, buildno, testname, core_prov, fabric,
mpitype, hosts, ofi_build_mode, util_prov)
self.mpichsuitepath = "{}/{}/mpichsuite/test/mpi/" \
.format(self.libfab_installpath, self.mpi)
self.pwd = os.getcwd()
def testgroup(self, testgroupname):
testpath = "{}/{}".format(self.mpichsuitepath, testgroupname)
tests = []
with open("{}/testlist".format(testpath)) as file:
for line in file:
if(line[0] != '#' and line[0] != '\n'):
tests.append((line.rstrip('\n')).split(' '))
return tests
def options(self, nprocs, timeout=None):
if (self.mpi == "impi" or self.mpi == "mpich"):
if (self.mpi == "impi"):
mpiroot = ci_site_config.impi_root
else:
mpiroot = "{}/mpich".format(self.libfab_installpath)
if (self.util_prov):
prov = "\"{};{}\"".format(self.core_prov, self.util_prov)
else:
prov = self.core_prov
if (timeout != None):
os.environ['MPIEXEC_TIMEOUT']=timeout
opts = "-n {np} -hosts {s},{c} -mpi_root={mpiroot} \
-libfabric_path={installpath}/lib -prov {provider} " \
.format(np=nprocs, s=self.server, c=self.client, \
provider=prov, mpiroot=mpiroot, \
installpath=self.libfab_installpath)
elif (self.mpi == "ompi"):
print(self.mpi)
return opts
@property
def execute_condn(self):
return True if (self.mpi == 'impi' and self.core_prov != 'psm2') else False
def execute_cmd(self, testgroupname):
print("Running Tests: " + testgroupname)
tests = []
time = None
os.chdir("{}/{}".format(self.mpichsuitepath,testgroupname))
tests = self.testgroup(testgroupname)
for test in tests:
testname = test[0]
nprocs = test[1]
args = test[2:]
for item in args:
itemlist = item.split('=')
if (itemlist[0] == 'timelimit'):
time = itemlist[1]
opts = self.options(nprocs, timeout=time)
testcmd = self.cmd + opts +"./{}".format(testname)
outputcmd = shlex.split(testcmd)
common.run_command(outputcmd)
os.chdir(self.pwd)
class MpiTestStress(MpiTests):
def __init__(self, jobname, buildno, testname, core_prov, fabric,
mpitype, hosts, ofi_build_mode, util_prov=None):
super().__init__(jobname, buildno, testname, core_prov, fabric,
mpitype, hosts, ofi_build_mode, util_prov)
if((self.core_prov == "verbs" or self.core_prov =="psm2")):
self.n = 16
self.ppn = 8
else:
self.n = 4
self.ppn = 2
@property
def stress_cmd(self):
return "{}/{}/stress/mpi_stress -dcr".format(self.libfab_installpath, self.mpi)
@property
def execute_condn(self):
# Todo : run stress test for ompi with libfabirc-dbg builds if it works
# in Jenkins for buildbot these ompi did not build with libfabric-dbg
# Due to an mpich issue when the correct mpich options are enabled during
# mpich builds, sttress test is failing. disabling mpich + stress tests
# untill the mpich team fixes the issue.
return True if (self.mpi != 'mpich' and (self.mpi != 'ompi' or \
self.ofi_build_mode != 'dbg')) else False
def execute_cmd(self):
command = self.cmd + self.options + self.stress_cmd
outputcmd = shlex.split(command)
common.run_command(outputcmd)
class MpiTestOSU(MpiTests):
def __init__(self, jobname, buildno, testname, core_prov, fabric,
mpitype, hosts, ofi_build_mode, util_prov=None):
super().__init__(jobname, buildno, testname, core_prov, fabric,
mpitype, hosts, ofi_build_mode, util_prov)
self.n = 4
self.ppn = 2
self.two_proc_tests = {'osu_latency',
'osu_bibw',
'osu_latency_mt',
'osu_bw','osu_get_latency',
'osu_fop_latency',
'osu_acc_latency',
'osu_get_bw',
'osu_put_latency',
'osu_put_bw',
'osu_put_bibw',
'osu_cas_latency',
'osu_get_acc_latency'
}
self.osu_mpi_path = "{}/{}/osu/libexec/osu-micro-benchmarks/mpi/". \
format(self.libfab_installpath,mpitype)
@property
def execute_condn(self):
# sockets and psm2 have some issues with OSU benchmark testing.
return True if (self.mpi != "ompi" or \
(self.core_prov != "sockets" and \
self.core_prov != "psm2" and \
self.ofi_build_mode!="dbg")) \
else False
def execute_cmd(self):
assert(self.osu_mpi_path)
p = re.compile('osu_put*')
for root, dirs, tests in os.walk(self.osu_mpi_path):
for test in tests:
if test in self.two_proc_tests:
self.n=2
self.ppn=1
else:
self.n=4
self.ppn=2
# for sockets provider skip 'osu_put' benchmark tests as they fail.
if(self.core_prov !='sockets' or p.search(test)== None):
launcher = self.cmd + self.options
osu_cmd = os.path.join(root, test)
command = launcher + osu_cmd
outputcmd = shlex.split(command)
common.run_command(outputcmd)