From 05b6ac16bcc3c8bb802cbd6af0bd3b10bd15a258 Mon Sep 17 00:00:00 2001 From: Tamara Dahlgren <35777542+tldahlgren@users.noreply.github.com> Date: Mon, 26 Jun 2023 03:40:03 -0700 Subject: tests/*mpi*: convert to new stand-alone test process (#35802) --- var/spack/repos/builtin/packages/mpi/package.py | 21 ++- var/spack/repos/builtin/packages/mpich/package.py | 62 ++++++--- .../repos/builtin/packages/openmpi/package.py | 151 +++++++-------------- 3 files changed, 99 insertions(+), 135 deletions(-) diff --git a/var/spack/repos/builtin/packages/mpi/package.py b/var/spack/repos/builtin/packages/mpi/package.py index 4e192e51b4..409331e6a3 100644 --- a/var/spack/repos/builtin/packages/mpi/package.py +++ b/var/spack/repos/builtin/packages/mpi/package.py @@ -14,20 +14,19 @@ class Mpi(Package): homepage = "https://www.mpi-forum.org/" virtual = True - def test(self): + def test_mpi_hello(self): + """build and run mpi hello world""" for lang in ("c", "f"): filename = self.test_suite.current_test_data_dir.join("mpi_hello." + lang) compiler_var = "MPICC" if lang == "c" else "MPIF90" - compiler = os.environ[compiler_var] + compiler = which(os.environ[compiler_var]) + mpirun = which(self.prefix.bin.mpirun) exe_name = "mpi_hello_%s" % lang - mpirun = join_path(self.prefix.bin, "mpirun") - - compiled = self.run_test(compiler, options=["-o", exe_name, filename]) - if compiled: - self.run_test( - mpirun, - options=["-np", "1", exe_name], - expected=[r"Hello world! From rank \s*0 of \s*1"], - ) + + with test_part(self, f"test_mpi_hello_{lang}", purpose=f"build and run {filename}"): + compiler("-o", exe_name, filename) + out = mpirun("-np", "1", exe_name, output=str.split, error=str.split) + expected = [r"Hello world! From rank \s*0 of \s*1"] + check_outputs(expected, out) diff --git a/var/spack/repos/builtin/packages/mpich/package.py b/var/spack/repos/builtin/packages/mpich/package.py index 581f4d0d31..e07b7c4759 100644 --- a/var/spack/repos/builtin/packages/mpich/package.py +++ b/var/spack/repos/builtin/packages/mpich/package.py @@ -600,27 +600,47 @@ with '-Wl,-commons,use_dylibs' and without install test subdirectory for use during `spack test run`.""" self.cache_extra_test_sources(["examples", join_path("test", "mpi")]) - def run_mpich_test(self, example_dir, exe): - """Run stand alone tests""" - - test_dir = join_path(self.test_suite.current_test_cache_dir, example_dir) - exe_source = join_path(test_dir, "{0}.c".format(exe)) - - if not os.path.isfile(exe_source): - print("Skipping {0} test".format(exe)) - return + def mpi_launcher(self): + """Determine the appropriate launcher.""" + commands = [ + join_path(self.spec.prefix.bin, "mpirun"), + join_path(self.spec.prefix.bin, "mpiexec"), + ] + if "+slurm" in self.spec: + commands.insert(0, join_path(self.spec["slurm"].prefix.bin)) + return which(*commands) + + def run_mpich_test(self, subdir, exe, num_procs=1): + """Compile and run the test program.""" + path = self.test_suite.current_test_cache_dir.join(subdir) + with working_dir(path): + src = f"{exe}.c" + if not os.path.isfile(src): + raise SkipTest(f"{src} is missing") + + mpicc = which(os.environ["MPICC"]) + mpicc("-Wall", "-g", "-o", exe, src) + if num_procs > 1: + launcher = self.mpi_launcher() + if launcher is not None: + launcher("-n", str(num_procs), exe) + return + + test_exe = which(exe) + test_exe() + + def test_cpi(self): + """build and run cpi""" + self.run_mpich_test("examples", "cpi") - self.run_test( - self.prefix.bin.mpicc, - options=[exe_source, "-Wall", "-g", "-o", exe], - purpose="test: generate {0} file".format(exe), - work_dir=test_dir, - ) + def test_finalized(self): + """build and run finalized""" + self.run_mpich_test(join_path("test", "mpi", "init"), "finalized") - self.run_test(exe, purpose="test: run {0} example".format(exe), work_dir=test_dir) + def test_manyrma(self): + """build and run manyrma""" + self.run_mpich_test(join_path("test", "mpi", "perf"), "manyrma", 2) - def test(self): - self.run_mpich_test(join_path("test", "mpi", "init"), "finalized") - self.run_mpich_test(join_path("test", "mpi", "basic"), "sendrecv") - self.run_mpich_test(join_path("test", "mpi", "perf"), "manyrma") - self.run_mpich_test("examples", "cpi") + def test_sendrecv(self): + """build and run sendrecv""" + self.run_mpich_test(join_path("test", "mpi", "basic"), "sendrecv", 2) diff --git a/var/spack/repos/builtin/packages/openmpi/package.py b/var/spack/repos/builtin/packages/openmpi/package.py index e4fb370d2d..3f3d59dfa7 100644 --- a/var/spack/repos/builtin/packages/openmpi/package.py +++ b/var/spack/repos/builtin/packages/openmpi/package.py @@ -1150,28 +1150,27 @@ class Openmpi(AutotoolsPackage, CudaPackage): """ self.cache_extra_test_sources(self.extra_install_tests) - def _test_bin_ops(self): - info = ([], ["Ident string: {0}".format(self.spec.version), "MCA"], 0) - - ls = (["-n", "1", "ls", ".."], ["openmpi-{0}".format(self.spec.version)], 0) - - checks = { - "mpirun": ls, - "ompi_info": info, - "oshmem_info": info, - "oshrun": ls, - "shmemrun": ls, - } - - for binary in checks: - options, expected, status = checks[binary] - exe = join_path(self.prefix.bin, binary) - reason = "test: checking {0} output".format(binary) - self.run_test( - exe, options, expected, status, installed=True, purpose=reason, skip_missing=True - ) - - def _test_check_versions(self): + def run_installed_binary(self, bin, options, expected): + """run and check outputs for the installed binary""" + exe_path = join_path(self.prefix.bin, bin) + if not os.path.exists(exe_path): + raise SkipTest(f"{bin} is not installed") + + exe = which(exe_path) + out = exe(*options, output=str.split, error=str.split) + check_outputs(expected, out) + + def test_mpirun(self): + """test installed mpirun""" + options = ["-n", "1", "ls", ".."] + self.run_installed_binary("mpirun", options, [f"openmpi-{self.spec.version}"]) + + def test_opmpi_info(self): + """test installed mpirun""" + self.run_installed_binary("ompi_info", [], [f"Ident string: {self.spec.version}", "MCA"]) + + def test_version(self): + """check versions of installed software""" comp_vers = str(self.spec.compiler.version) spec_vers = str(self.spec.version) checks = { @@ -1188,116 +1187,62 @@ class Openmpi(AutotoolsPackage, CudaPackage): "ompi_info": spec_vers, "ortecc": comp_vers, "orterun": spec_vers, - # Binaries available in versions 2.0.0 through 2.1.6 - "ompi-submit": spec_vers, - "orte-submit": spec_vers, - # Binaries available in versions 2.0.0 through 3.1.5 - "ompi-dvm": spec_vers, - "orte-dvm": spec_vers, - "oshcc": comp_vers, - "oshfort": comp_vers, - "oshmem_info": spec_vers, - "oshrun": spec_vers, - "shmemcc": comp_vers, - "shmemfort": comp_vers, - "shmemrun": spec_vers, - # Binary available in version 3.1.0 through 3.1.5 - "prun": spec_vers, - # Binaries available in versions 3.0.0 through 3.1.5 - "oshCC": comp_vers, - "oshc++": comp_vers, - "oshcxx": comp_vers, - "shmemCC": comp_vers, - "shmemc++": comp_vers, - "shmemcxx": comp_vers, } - for binary in checks: - expected = checks[binary] - purpose = "test: ensuring version of {0} is {1}".format(binary, expected) - exe = join_path(self.prefix.bin, binary) - self.run_test( - exe, "--version", expected, installed=True, purpose=purpose, skip_missing=True - ) + for bin in checks: + expected = checks[bin] + with test_part( + self, f"test_version_{bin}", purpose=f"ensure version of {bin} is {expected}" + ): + self.run_installed_binary(bin, ["--version"], [expected]) @property def _cached_tests_work_dir(self): """The working directory for cached test sources.""" return join_path(self.test_suite.current_test_cache_dir, self.extra_install_tests) - def _test_examples(self): + def test_example(self): """Run test examples copied from source at build-time.""" # Build the copied, cached test examples - self.run_test( - "make", - ["all"], - [], + with test_part( + self, + "test_example_make", purpose="test: building cached test examples", work_dir=self._cached_tests_work_dir, - ) + ): + make("all") - # Run examples with known, simple-to-verify results - have_spml = self.spec.satisfies("@2:2.1.6") - - hello_world = (["Hello, world", "I am", "0 of", "1"], 0) - - max_red = (["0/1 dst = 0 1 2"], 0) - - missing_spml = (["No available spml components"], 1) - - no_out = ([""], 0) - - ring_out = (["1 processes in ring", "0 exiting"], 0) - - strided = (["not in valid range"], 255) + # Run basic examples with known, simple-to-verify results + hello_world = ["Hello, world", "I am", "0 of", "1"] + ring_out = ["1 processes in ring", "0 exiting"] checks = { "hello_c": hello_world, "hello_cxx": hello_world, "hello_mpifh": hello_world, - "hello_oshmem": hello_world if have_spml else missing_spml, - "hello_oshmemcxx": hello_world if have_spml else missing_spml, - "hello_oshmemfh": hello_world if have_spml else missing_spml, "hello_usempi": hello_world, "hello_usempif08": hello_world, - "oshmem_circular_shift": ring_out if have_spml else missing_spml, - "oshmem_max_reduction": max_red if have_spml else missing_spml, - "oshmem_shmalloc": no_out if have_spml else missing_spml, - "oshmem_strided_puts": strided if have_spml else missing_spml, - "oshmem_symmetric_data": no_out if have_spml else missing_spml, "ring_c": ring_out, "ring_cxx": ring_out, "ring_mpifh": ring_out, - "ring_oshmem": ring_out if have_spml else missing_spml, - "ring_oshmemfh": ring_out if have_spml else missing_spml, "ring_usempi": ring_out, "ring_usempif08": ring_out, } - for exe in checks: - expected, status = checks[exe] - reason = "test: checking {0} example output and status ({1})".format(exe, status) - self.run_test( - exe, - [], - expected, - status, - installed=False, - purpose=reason, - skip_missing=True, + for binary in checks: + expected = checks[binary] + with test_part( + self, + f"test_example_{binary}", + purpose="run and check output", work_dir=self._cached_tests_work_dir, - ) - - def test(self): - """Perform stand-alone/smoke tests on the installed package.""" - # Simple version check tests on selected installed binaries - self._test_check_versions() - - # Test the operation of selected executables - self._test_bin_ops() + ): + exe = which(binary) + if not exe: + raise SkipTest(f"{binary} is missing") - # Test example programs pulled from the build - self._test_examples() + out = exe(output=str.split, error=str.split) + check_outputs(expected, out) def get_spack_compiler_spec(compiler): -- cgit v1.2.3-60-g2f50