diff --git a/docs/content/docs/building.mdx b/docs/content/docs/building.mdx index 3310a4ee..8544121b 100644 --- a/docs/content/docs/building.mdx +++ b/docs/content/docs/building.mdx @@ -440,6 +440,10 @@ requests that touch `tools/container/` or the workflow. `tools/container/smoke-t checks the monoprop image before it is pushed. It never imports monoprop, because the CI machine's CPU may lack the instructions `-march` enables, so check a new image on the target machine as well (see [MareNostrum5](/clusters/marenostrum5#check-the-image)). +Being a source build, the image has a single MPI backend, for the ABI family of the base +image's Open MPI; the smoke test checks that mpi4py loads that same family, without which +propagators given a communicator raise +[MPIAbiMismatchError][monoprop.exceptions.MPIAbiMismatchError]. To reproduce the build locally: diff --git a/docs/content/docs/clusters/index.mdx b/docs/content/docs/clusters/index.mdx index acb66b83..f97d65e4 100644 --- a/docs/content/docs/clusters/index.mdx +++ b/docs/content/docs/clusters/index.mdx @@ -3,8 +3,10 @@ title: HPC clusters description: Running monoprop on HPC systems from its MPI-enabled container image. --- -Some HPC systems give their login nodes no outbound network, so monoprop cannot be -installed there with `pip`. For those, every release, the `main` branch and pull requests that +Where `pip` works, `pip install "monoprop[mpi]"` installs wheels that run on the cluster's own +MPI, if it is from the MPICH family (MPICH, Intel MPI, MVAPICH, Cray MPICH) or Open MPI and +not older than the versions listed in [Enabling MPI](/features/parallelism#enabling-mpi). Some HPC systems, however, give their login +nodes no outbound network, so monoprop cannot be installed there with `pip`. For those, every release, the `main` branch and pull requests that change the container recipes publish an MPI-enabled container image to the GitHub Container Registry: ```text diff --git a/docs/content/docs/clusters/marenostrum5.mdx b/docs/content/docs/clusters/marenostrum5.mdx index 4c77ecbb..b7895662 100644 --- a/docs/content/docs/clusters/marenostrum5.mdx +++ b/docs/content/docs/clusters/marenostrum5.mdx @@ -30,18 +30,28 @@ rsync -P monoprop_.sif @:/ ## Check the image -Get an interactive allocation on a compute node, then check that monoprop imports and sees -MPI on two ranks: +Get an interactive allocation on a compute node, then check that monoprop runs a propagator +over MPI on two ranks: ```bash salloc --nodes=1 --account= -q gp_debug --exclusive --time=00:10:00 module load singularity -srun -n 2 --mpi=pmix singularity exec monoprop_.sif \ - python3 -c 'import monoprop; print(monoprop.__version__, monoprop.has_mpi)' +srun -n 2 --mpi=pmix singularity exec monoprop_.sif python3 -c ' +import monoprop +from mpi4py import MPI +comm = MPI.COMM_WORLD.Dup() +operator = monoprop.PauliOperator({monoprop.Pauli("Z", (0,)): 1.0}, 2) +propagator = monoprop.PauliPropagator(operator, [0], cutoff=2, comm=comm) +print(comm.Get_rank(), monoprop.__version__, "MPI backend loaded") +del propagator +comm.Free()' ``` -Both ranks should print the image's version and `True`. This is the check CI cannot run: -the CI machines may lack the Sapphire Rapids instructions the image is compiled for. +Each rank should print its rank, the image's version and `MPI backend loaded`. Building a +propagator with a communicator loads monoprop's MPI backend for the MPI library mpi4py uses, +so this also checks that the image's mpi4py and monoprop agree on it; if they did not, it would +raise [MPIAbiMismatchError][monoprop.exceptions.MPIAbiMismatchError]. This is the check CI +cannot run: the CI machines may lack the Sapphire Rapids instructions the image is compiled for. MN5's Slurm offers munge authentication to PMIx, which the container's PMIx is built without. The image sets `PMIX_MCA_psec=native`, so the ranks use PMIx's native diff --git a/tools/container/smoke-test.sh b/tools/container/smoke-test.sh index 13d5841b..f25584ad 100755 --- a/tools/container/smoke-test.sh +++ b/tools/container/smoke-test.sh @@ -53,6 +53,36 @@ echo "$mpi4py_library" [[ "$mpi4py_library" == *"Open MPI v${ompi_version}"* ]] \ || fail "mpi4py did not load the image's Open MPI v$ompi_version" +echo "== MPI ABI of monoprop's backend" +# monoprop loads its MPI extension for the ABI family mpi4py uses, and raises if it was not +# built for that family. Both sides are read from files, so monoprop is still not imported. +abi_check="$(python3 - "$package_dir" <<'PY' +import ast +import pathlib +import re +import sys + +import mpi4py + +mpi4py.rc.initialize = False +from mpi4py import MPI + +source = (pathlib.Path(sys.argv[1]) / "_mpi_abis.py").read_text() +built = next( + ast.literal_eval(node.value) + for node in ast.parse(source).body + if isinstance(node, ast.AnnAssign) and getattr(node.target, "id", "") == "ABIS" +) +variant = re.match(r"MPI\.(mpich|openmpi|mpiabi)\.", pathlib.Path(MPI.__spec__.origin).name) +print(" ".join(built), variant[1] if variant else "unknown", sep="|") +PY +)" +built_abis="${abi_check%|*}" +mpi4py_abi="${abi_check#*|}" +echo "built for: ${built_abis:-none}; mpi4py uses: $mpi4py_abi" +[[ " $built_abis " == *" $mpi4py_abi "* ]] \ + || fail "mpi4py uses the $mpi4py_abi MPI ABI, but monoprop was built for: ${built_abis:-none}" + echo "== Open MPI build" grep -q 'MCA pml: ucx' <<< "$ompi_details" || fail "Open MPI was built without the UCX PML" # The base image builds PMIx into /usr/local/pmix; srun --mpi=pmix talks to it.