-
-
Notifications
You must be signed in to change notification settings - Fork 242
Detect MPI with Singularity #2216
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
kinow
wants to merge
1
commit into
main
Choose a base branch
from
detect-mpi-with-singularity
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| """Support for executing Docker format containers using Singularity {2,3}.x or Apptainer 1.x.""" | ||
|
|
||
| import atexit | ||
| import copy | ||
| import hashlib | ||
| import json | ||
|
|
@@ -11,7 +12,10 @@ | |
| import sys | ||
| import threading | ||
| from collections.abc import Callable, MutableMapping, MutableSequence | ||
| from contextlib import suppress | ||
| from importlib.resources import files as resource_files | ||
| from subprocess import check_call, check_output, run # nosec | ||
| from tempfile import NamedTemporaryFile | ||
| from typing import cast | ||
|
|
||
| from cwl_utils.types import CWLDirectoryType, CWLFileType, CWLObjectType | ||
|
|
@@ -29,6 +33,7 @@ | |
| from .errors import WorkflowException | ||
| from .job import ContainerCommandLineJob | ||
| from .loghandler import _logger | ||
| from .mpi import MPIRequirementName | ||
| from .pathmapper import MapperEnt, PathMapper | ||
| from .singularity_utils import singularity_supports_userns | ||
| from .utils import create_tmp_dir, ensure_non_writable, ensure_writable | ||
|
|
@@ -203,7 +208,7 @@ def __init__( | |
| hints: list[CWLObjectType], | ||
| name: str, | ||
| ) -> None: | ||
| """Builder for invoking the Singularty software container engine.""" | ||
| """Builder for invoking the Singularity software container engine.""" | ||
| super().__init__(builder, joborder, make_path_mapper, requirements, hints, name) | ||
|
|
||
| @staticmethod | ||
|
|
@@ -592,14 +597,55 @@ def create_runtime( | |
| """Return the Singularity runtime list of commands and options.""" | ||
| any_path_okay = self.builder.get_requirement("DockerRequirement")[1] or False | ||
|
|
||
| runtime = [ | ||
| "singularity", | ||
| "--quiet", | ||
| "run" if (is_apptainer_1_1_or_newer() or is_version_3_10_or_newer()) else "exec", | ||
| "--contain", | ||
| "--ipc", | ||
| "--cleanenv", | ||
| ] | ||
| mpi_req, is_req = self.builder.get_requirement(MPIRequirementName) | ||
| mpi_enabled = mpi_req and is_req | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the |
||
| mpi_config = runtime_context.mpi_config | ||
| mpi_env_vars_reference_file_name: str | None = None | ||
| runtime: list[str] = [] | ||
| if mpi_enabled: | ||
| # Save current environment variables. The ``singularity_wrapper.sh`` will | ||
| # diff it against the env vars produced by mpirun/srun/etc., and use the new | ||
| # env vars as SINGULARITYENV_... for Singularity. | ||
| with NamedTemporaryFile(mode="w+", delete=False) as f: | ||
| for k, v in os.environ.items(): | ||
| f.write(f"{k}={v}\n") | ||
| mpi_env_vars_reference_file_name = f.name | ||
|
|
||
| def delete_mpi_baseline_env() -> None: | ||
| """Clean up the MPI baseline environment variables file at exit.""" | ||
| with suppress(FileNotFoundError): # pragma: no cover | ||
| os.remove(mpi_env_vars_reference_file_name) # pragma: no cover | ||
|
|
||
| atexit.register(delete_mpi_baseline_env) | ||
|
|
||
| runtime.extend( | ||
| [ | ||
| str(resource_files("cwltool") / "singularity_wrapper.sh"), | ||
| mpi_env_vars_reference_file_name, | ||
| "singularity", | ||
| ] | ||
| ) | ||
| else: | ||
| runtime.append("singularity") | ||
|
|
||
| runtime.extend( | ||
| [ | ||
| "--quiet", | ||
| "run" if (is_apptainer_1_1_or_newer() or is_version_3_10_or_newer()) else "exec", | ||
| "--contain", | ||
| "--ipc", | ||
| "--cleanenv", | ||
| ] | ||
| ) | ||
| if mpi_enabled and mpi_config.shm_enabled: | ||
| # MPI implementations like OpenMPI and MPICH use shared memory. | ||
| self.append_volume( | ||
| runtime, | ||
| runtime_context.create_tmpdir(), | ||
| mpi_config.shm_dir, | ||
| writable=True, | ||
| ) | ||
|
|
||
| if is_apptainer_1_1_or_newer() or is_version_3_10_or_newer(): | ||
| runtime.append("--no-eval") | ||
|
|
||
|
|
@@ -665,4 +711,4 @@ def create_runtime( | |
| if container_HOME: | ||
| # Restore HOME if we removed it above. | ||
| self.environment["HOME"] = container_HOME | ||
| return (runtime, None) | ||
| return runtime, None | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
| #!/usr/bin/env bash | ||
| set -euo pipefail | ||
|
|
||
| # singularity_wrapper.sh | ||
| # | ||
| # DESCRIPTION | ||
| # Wrapper around Singularity/Apptainer for CWL + MPI + Singularity. | ||
| # | ||
| # This script identifies environment variables added by an MPI launcher | ||
| # (e.g. srun, mpirun) and adds these environment variables as Singularity | ||
| # environment variables using the format ``SINGULARITYENV_$KEY=$VALUE``. | ||
| # | ||
| # This allows CWL (which uses ``--cleanenv``) to launch MPI + Singularity. | ||
| # | ||
| # USAGE | ||
| # singularity_wrapper.sh <baseline-env-file> <singularity-bin> <args> | ||
| # | ||
| # ARGUMENTS | ||
| # <baseline-env-file> | ||
| # Path to the file containing KEY=VALUE pairs with the baseline env. | ||
| # | ||
| # <singularity-bin> | ||
| # Path to singularity/apptainer executable. | ||
| # | ||
| # [args...] | ||
| # Arguments passed to the singularity binary. | ||
| # | ||
| # EXAMPLE | ||
| # singularity_wrapper.sh env.txt singularity --cleanenv exec image.sif | ||
| # | ||
| # DEPENDENCIES | ||
| # It uses the following binaries: | ||
| # - printenv | ||
|
|
||
| usage() { | ||
| cat >&2 <<EOF | ||
| singularity_wrapper.sh | ||
|
|
||
| Wrapper around Singularity/Apptainer for CWL + MPI + Singularity. | ||
|
|
||
| USAGE: | ||
| singularity_wrapper.sh <baseline-env-file> <singularity-bin> [args...] | ||
| EOF | ||
| exit 1 | ||
| } | ||
|
|
||
| if [[ "${1:-}" == "--help" ]]; then | ||
| usage | ||
| fi | ||
|
|
||
| [[ $# -ge 2 ]] || usage | ||
|
|
||
| BASELINE_FILE="$1" | ||
| SINGULARITY_BIN="$2" | ||
| shift 2 | ||
|
|
||
| if [[ ! -f "$BASELINE_FILE" ]]; then | ||
| echo "Error: baseline env file not found: $BASELINE_FILE" >&2 | ||
| exit 2 | ||
| fi | ||
|
|
||
| # Read baseline env into a variable. | ||
| BASELINE_CONTENT=$'\n'"$(cat "$BASELINE_FILE")"$'\n' | ||
|
|
||
| # Build new environment variables for Singularity (i.e. ``SINGULARITYENV_KEY=VALUE``). | ||
| # Excludes empty variables and variables whose name do not follow POSIX (e.g. some | ||
| # Bash environments on HPC clusters such as BSC MareNostrum5, ``BASH_FUNC_module%%=``). | ||
| while IFS='=' read -r k v; do | ||
| [[ -n "$k" ]] || continue | ||
| [[ "$k" =~ ^[A-Za-z_][A-Za-z0-9_]*$ ]] || continue | ||
| # If the current env doesn't exist (``! -z``) in the given baseline env (``BASE_ENV``), | ||
| # then we want to add it as ``--env`` in singularity. | ||
| # Check if the key exists in the BASELINE_CONTENT string in the | ||
| # form \n$KEY= (that's why we start the BASELINE and end it with \n). | ||
| if [[ ! "$BASELINE_CONTENT" == *$'\n'"$k"=* ]]; then | ||
| # Debug | ||
| # echo "Adding env var for Singularity command: SINGULARITYENV_$k=$v" >&2 | ||
| export "SINGULARITYENV_$k=$v" | ||
| fi | ||
| done < <(printenv) | ||
|
|
||
| # Launch the Singularity binary. | ||
| exec "$SINGULARITY_BIN" "${@}" |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like FreeBSD uses objects instead of files as in Linux:
https://man.freebsd.org/cgi/man.cgi?shm_open#:~:text=The%20shm%5Fopen%28%29%20and%20shm%5Funlink%28%29%20functions%20first%20appeared%20in%20FreeBSD%204%2E3%2E%20The%20functions%20were%20reimplemented%20as%20system%20calls%20using%20shared%20memory%20objects%20directly%20rather%20than%20files%20in%20FreeBSD%208%2E0%2E
These two, shm_enabled and shm_dir, are used to control whether the shared memory will be used and the directory to be used, respect/.
And MPICH allows users to disable the shared memory completely, or change its size. https://github.com/pmodels/mpich/blob/main/doc/wiki/faq/Frequently_Asked_Questions.md#:~:text=The%20work,stack
So with these settings I think users are able to match the behavior of that implementation at least.