diff --git a/.github/actions/docker-build/action.yaml b/.github/actions/docker-build/action.yaml new file mode 100644 index 0000000000..0c9318740e --- /dev/null +++ b/.github/actions/docker-build/action.yaml @@ -0,0 +1,53 @@ +name: Docker build action +description: Composite action for building Devito Docker containers +author: "Devito" + +inputs: +# The only supported GHA input type is string + file: + description: "Dockerfile containing build instructions" + required: true + default: Dockerfile + tag: + description: "Tag to add to the built image" + required: true + base: + description: "Base docker image to build on top of" + required: true + +outputs: + unique: + description: "Unique identifier for the CI run" + value: ${{ steps.uniquetag.outputs.unique }} + +runs: + using: "composite" + steps: + - id: uniquetag + name: "Generate unique CI tag" + shell: bash + run: | + UNIQUE=$(echo "${GITHUB_RUN_ID}_${GITHUB_RUN_ATTEMPT}" | cksum | cut -f 1 -d " ") + echo "Unique ID: ${UNIQUE}" + echo "unique=${UNIQUE}" >> "$GITHUB_OUTPUT" + + - id: dockerbuild + name: "Build docker container" + shell: bash + run: | + docker build \ + --pull \ + --file ${{ inputs.file }} \ + --tag ${{ inputs.tag }}_${{ steps.uniquetag.outputs.unique }} \ + --build-arg base=${{ inputs.base }} \ + . + +# Do we need to be more specific? +#~ docker buildx build . \ + #~ --builder "${RUNNER_NAME// /_}" \ + #~ --load \ + #~ --label ci-run="$GITHUB_RUN_ID" \ + #~ --rm --pull \ + #~ --file docker/Dockerfile.devito \ + #~ --tag "${DOCKER_IMAGE}" \ + #~ --build-arg base="${{ matrix.base }}" diff --git a/.github/actions/docker-clean/action.yaml b/.github/actions/docker-clean/action.yaml new file mode 100644 index 0000000000..56bf2f88ab --- /dev/null +++ b/.github/actions/docker-clean/action.yaml @@ -0,0 +1,21 @@ +name: Docker cleanup action +description: Composite action for removing Docker images +author: "Devito" + +inputs: +# The only supported GHA input type is string + uid: + description: "Unique identifier output from docker-build action" + required: true + tag: + description: "Tag of the built image to use" + required: true + +runs: + using: "composite" + steps: + - id: dockerclean + name: "Cleanup docker image" + shell: bash + run: | + docker image rm -f "${{ inputs.tag }}_${{ inputs.uid }}" diff --git a/.github/actions/docker-run/action.yaml b/.github/actions/docker-run/action.yaml new file mode 100644 index 0000000000..51c6134d6e --- /dev/null +++ b/.github/actions/docker-run/action.yaml @@ -0,0 +1,56 @@ +name: Docker run action +description: Composite action for running commands in Docker containers +author: "Devito" + +inputs: +# The only supported GHA input type is string + uid: + description: "Unique identifier output from docker-build action" + required: true + args: + description: "Arguments to pass to `docker run`" + required: true + default: "" + env: + description: "Environment variables to set inside the docker container" + required: true + default: Dockerfile + tag: + description: "Tag of the built image to use" + required: true + command: + description: "Command to execute inside of the docker container" + required: true + +runs: + using: "composite" + steps: + - id: processenv + name: Process environment variable list + shell: bash + env: + ENV_INPUT: ${{ inputs.env }} + run: | + ENV_STRING="" + # Read line by line with here string, safely handling spaces within the values + while IFS= read -r LINE; do + if [[ -n "$LINE" ]]; then + ENV_STRING="$ENV_STRING --env $LINE" + fi + done <<< "$ENV_INPUT" + # Remove the leading space from the first concatenation + ENV_STRING="${ENV_STRING# }" + echo "env=$ENV_STRING" >> "$GITHUB_OUTPUT" + + - id: dockerrun + name: "Run command ${{ inputs.command }} in ${{ inputs.tag }} docker container" + shell: bash + run: | + docker run \ + --init -t --rm \ + ${{ inputs.args }} \ + --name "ci-${{ inputs.name }}-${{ inputs.uid }}" \ + --env-file=docker/coverage.env \ + ${{ steps.processenv.outputs.env }} \ + "${{ inputs.tag }}_${{ inputs.uid }}" \ + ${{ inputs.command }} diff --git a/.github/workflows/pytest-core-mpi.yaml b/.github/workflows/pytest-core-mpi.yaml index 6923691723..f21851b0a8 100644 --- a/.github/workflows/pytest-core-mpi.yaml +++ b/.github/workflows/pytest-core-mpi.yaml @@ -12,10 +12,10 @@ on: # but only for the main branch push: branches: - - main + - main pull_request: branches: - - main + - main jobs: test-mpi-basic: @@ -63,86 +63,73 @@ jobs: name: pytest-mpi test-mpi-docker: - name: pytest-mpi - runs-on: ${{ matrix.os }} - outputs: - unique : ${{ steps.uniquetag.outputs.unique }} - strategy: - matrix: - name: [gcc, gcc-arm, icx] - include: - - name: gcc - arch: gcc - os: ubuntu-latest - mpiflag: "" - - - name: gcc-arm - arch: gcc - os: ubuntu-24.04-arm - mpiflag: "" - - - name: icx - arch: icx - os: ubuntu-latest - # Need safe math for icx due to inaccuracy with mpi+sinc interpolation - mpiflag: "-e DEVITO_SAFE_MATH=1" - - steps: - - name: Checkout devito - uses: actions/checkout@v6 - - - name: Generate unique CI tag - id: uniquetag - run: | - UNIQUE=$(echo "${GITHUB_RUN_ID}_${GITHUB_RUN_ATTEMPT}" | cksum | cut -f 1 -d " ") - echo "Unique ID: ${UNIQUE}" - echo "unique=${UNIQUE}" >> "$GITHUB_OUTPUT" - - - name: Build docker image - env: - UNIQUE: ${{ steps.uniquetag.outputs.unique }} - run: | - docker build \ - --file docker/Dockerfile.devito \ - --tag "devito_img${UNIQUE}" \ - --build-arg base=devitocodes/bases:cpu-${{ matrix.arch }} \ - . - - - name: Test with pytest - env: - UNIQUE: ${{ steps.uniquetag.outputs.unique }} - run: | - docker run \ - --init -t --rm \ - --env CODECOV_TOKEN=${{ secrets.CODECOV_TOKEN }} \ - --env OMP_NUM_THREADS=1 \ - --name testrun \ - "devito_img${UNIQUE}" \ - pytest tests/test_mpi.py - - - name: Test examples with MPI - env: - UNIQUE: ${{ steps.uniquetag.outputs.unique }} - run: | - docker run \ - --init -t --rm \ - ${{ matrix.mpiflag }} \ - --env DEVITO_MPI=1 \ - --env OMP_NUM_THREADS=1 \ - --name examplerun \ - "devito_img${UNIQUE}" \ - mpiexec -n 2 pytest examples/seismic/acoustic - # - docker run \ - --init -t --rm \ - --env DEVITO_MPI=1 \ - --env OMP_NUM_THREADS=1 \ - --name examplerun \ - "devito_img${UNIQUE}" \ - mpiexec -n 2 pytest examples/seismic/tti - - - name: Cleanup - env: - UNIQUE: ${{ steps.uniquetag.outputs.unique }} - run: | - docker image rm -f "devito_img${UNIQUE}" + name: pytest-mpi + runs-on: ${{ matrix.os }} + strategy: + matrix: + name: [ + pytest-mpi-docker-gcc, + pytest-mpi-docker-gcc-arm, + pytest-mpi-docker-icx + ] + include: + - name: pytest-mpi-docker-gcc + arch: gcc + os: ubuntu-latest + + - name: pytest-mpi-docker-gcc-arm + arch: gcc + os: ubuntu-24.04-arm + + - name: pytest-mpi-docker-icx + arch: icx + os: ubuntu-latest + + steps: + - name: Checkout devito + uses: actions/checkout@v6 + + - id: build + name: Build docker image + uses: ./.github/actions/docker-build + with: + file: docker/Dockerfile.devito + tag: ${{ matrix.name }} + base: devitocodes/bases:cpu-${{ matrix.arch }} + + - name: Test with pytest + uses: ./.github/actions/docker-run + with: + uid: ${{ steps.build.outputs.unique }} + tag: ${{ matrix.name }} + env: | + CODECOV_TOKEN=${{ secrets.CODECOV_TOKEN }} + OMP_NUM_THREADS=1 + command: "pytest tests/test_mpi.py" + + - name: Test acoustic example with MPI + uses: ./.github/actions/docker-run + with: + uid: ${{ steps.build.outputs.unique }} + tag: ${{ matrix.name }} + env: | + DEVITO_MPI=1 + OMP_NUM_THREADS=1 + command: "mpiexec -n 2 pytest examples/seismic/acoustic" + + - name: Test tti example with MPI + uses: ./.github/actions/docker-run + with: + uid: ${{ steps.build.outputs.unique }} + tag: ${{ matrix.name }} + env: | + DEVITO_MPI=1 + OMP_NUM_THREADS=1 + command: "mpiexec -n 2 pytest examples/seismic/tti" + + - name: Cleanup docker image + if: always() + uses: ./.github/actions/docker-clean + with: + uid: ${{ steps.build.outputs.unique }} + tag: ${{ matrix.name }} diff --git a/.github/workflows/pytest-core-nompi.yaml b/.github/workflows/pytest-core-nompi.yaml index 9fa6284f13..70f31fa7d6 100644 --- a/.github/workflows/pytest-core-nompi.yaml +++ b/.github/workflows/pytest-core-nompi.yaml @@ -18,7 +18,7 @@ on: - main jobs: - pytest: + test-nompi-basic: name: ${{ matrix.name }}-${{ matrix.set }} runs-on: "${{ matrix.os }}" @@ -27,25 +27,19 @@ jobs: DEVITO_LANGUAGE: ${{ matrix.language }} OMP_NUM_THREADS: 2 - outputs: - unique : ${{ steps.uniquetag.outputs.unique }} - strategy: # Prevent all build to stop if a single one fails fail-fast: false matrix: name: [ - pytest-ubuntu-py311-gcc11-cxxnoomp, - pytest-ubuntu-py312-gcc12-cxxomp, + pytest-osx-py312-clang-omp, pytest-ubuntu-py310-gcc14-omp, + pytest-ubuntu-py310-gcc9-omp, pytest-ubuntu-py311-gcc10-noomp, + pytest-ubuntu-py311-gcc11-cxxnoomp, + pytest-ubuntu-py312-gcc12-cxxomp, pytest-ubuntu-py312-gcc13-omp, - pytest-ubuntu-py310-gcc9-omp, - pytest-osx-py312-clang-omp, - pytest-docker-py310-gcc-omp, - pytest-docker-py310-gcc-omp-arm64, - pytest-docker-py310-icx-omp, pytest-ubuntu-py313-gcc14-omp ] set: [base, adjoint] @@ -100,27 +94,6 @@ jobs: language: "openmp" sympy: "1.12" - - name: pytest-docker-py310-gcc-omp - python-version: '3.10' - os: ubuntu-latest - arch: "gcc" - language: "openmp" - sympy: "1.13" - - - name: pytest-docker-py310-gcc-omp-arm64 - python-version: '3.10' - os: ubuntu-24.04-arm - arch: "gcc" - language: "openmp" - sympy: "1.13" - - - name: pytest-docker-py310-icx-omp - python-version: '3.10' - os: ubuntu-latest - arch: "icx" - language: "openmp" - sympy: "1.13" - - name: pytest-ubuntu-py313-gcc14-omp python-version: '3.13' os: ubuntu-24.04 @@ -143,47 +116,13 @@ jobs: uses: actions/checkout@v6 - name: Set up Python ${{ matrix.python-version }} - if: "!contains(matrix.name, 'docker')" uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} allow-prereleases: true - - name: Generate unique CI tag - id: uniquetag - run: | - UNIQUE=$(echo "${GITHUB_RUN_ID}_${GITHUB_RUN_ATTEMPT}" | cksum | cut -f 1 -d " ") - echo "Unique ID: ${UNIQUE}" - echo "unique=${UNIQUE}" >> "$GITHUB_OUTPUT" - - - name: Build docker image - if: contains(matrix.name, 'docker') - env: - UNIQUE: ${{ steps.uniquetag.outputs.unique }} - run: | - docker build \ - --file docker/Dockerfile.devito \ - --tag "devito_img${UNIQUE}" \ - --build-arg base=devitocodes/bases:cpu-${{ matrix.arch }} \ - . - - - name: Set run prefix - env: - UNIQUE: ${{ steps.uniquetag.outputs.unique }} - run: | - if [[ "${{ matrix.name }}" =~ "docker" ]]; then - echo "RUN_CMD=docker run \ - --init -t --rm \ - --env CODECOV_TOKEN=${{ secrets.CODECOV_TOKEN }} \ - --name testrun \ - devito_img${UNIQUE}" >> "$GITHUB_ENV" - else - echo "RUN_CMD=" >> "$GITHUB_ENV" - fi - id: set-run - - name: Install ${{ matrix.arch }} compiler - if: "runner.os == 'linux' && !contains(matrix.name, 'docker') && matrix.arch !='custom' " + if: "runner.os == 'linux' && matrix.arch !='custom' " run : | sudo apt-get install -y ${{ matrix.arch }} @@ -205,7 +144,6 @@ jobs: fi - name: Install dependencies - if: "!contains(matrix.name, 'docker')" run: | python3 -m pip install ${{ env.PIPFLAGS }} --upgrade pip python3 -m pip install ${{ env.PIPFLAGS }} -e ".[tests,extras]" @@ -215,27 +153,15 @@ jobs: if: matrix.name == 'pytest-ubuntu-py310-gcc14-omp' run: python3 -m pip install ${{ env.PIPFLAGS }} numpy==1.26 - - name: Check Docker image Python version - if: "contains(matrix.name, 'docker')" - run: | - declared_pyver="${{ matrix.python-version }}" - actual_pyver=$(${{ env.RUN_CMD }} python3 --version | grep "Python " | cut -d' ' -f2 | cut -d'.' -f1,2) - echo "Declared Python version: $declared_pyver" - echo "Actual Python version: $actual_pyver" - if [ "$declared_pyver" != "$actual_pyver" ]; then - echo "Python version mismatch: declared $declared_pyver, image has $actual_pyver" - exit 1 - fi - - name: Check configuration run: | - ${{ env.RUN_CMD }} python3 \ + python3 \ -c "from devito import configuration; \ print(''.join(['%s: %s \n' % (k, v) for (k, v) in configuration.items()]))" - name: Test with pytest run: | - ${{ env.RUN_CMD }} pytest \ + pytest \ -k "${{ matrix.test-set }}" \ -m "not parallel" \ --cov \ @@ -244,15 +170,110 @@ jobs: tests/ - name: Upload coverage to Codecov - if: "!contains(matrix.name, 'docker')" uses: codecov/codecov-action@v5 with: token: ${{ secrets.CODECOV_TOKEN }} name: ${{ matrix.name }} - - name: Cleanup Docker - if: "contains(matrix.name, 'docker')" - env: - UNIQUE: ${{ steps.uniquetag.outputs.unique }} + test-nompi-docker: + name: ${{ matrix.name }}-${{ matrix.set }} + runs-on: "${{ matrix.os }}" + + env: + DEVITO_ARCH: "${{ matrix.arch }}" + DEVITO_LANGUAGE: ${{ matrix.language }} + OMP_NUM_THREADS: 2 + + strategy: + # Prevent all build to stop if a single one fails + fail-fast: false + + matrix: + name: [ + pytest-docker-py310-gcc-omp, + pytest-docker-py310-gcc-omp-arm64, + pytest-docker-py310-icx-omp, + ] + set: [base, adjoint] + + include: + - name: pytest-docker-py310-gcc-omp + python-version: '3.10' + os: ubuntu-latest + arch: "gcc" + language: "openmp" + sympy: "1.13" + + - name: pytest-docker-py310-gcc-omp-arm64 + python-version: '3.10' + os: ubuntu-24.04-arm + arch: "gcc" + language: "openmp" + sympy: "1.13" + + - name: pytest-docker-py310-icx-omp + python-version: '3.10' + os: ubuntu-latest + arch: "icx" + language: "openmp" + sympy: "1.13" + + - set: base + test-set: 'not adjoint' + + - set: adjoint + test-set: 'adjoint' + + steps: + - name: Checkout devito + uses: actions/checkout@v6 + + - id: build + name: Build docker image + uses: ./.github/actions/docker-build + with: + file: docker/Dockerfile.devito + tag: ${{ matrix.name }} + base: devitocodes/bases:cpu-${{ matrix.arch }} + + - name: Get the Docker image Python version + uses: ./.github/actions/docker-run + with: + uid: ${{ steps.build.outputs.unique }} + tag: ${{ matrix.name }} + command: > + python3 --version | grep "Python " | cut -d' ' -f2 | cut -d'.' -f1,2 > dockerpythonversion.txt + + - name: Check Docker image Python version run: | - docker image rm -f "devito_img${UNIQUE}" + declared_pyver="${{ matrix.python-version }}" + actual_pyver=$(cat dockerpythonversion.txt) + echo "Declared Python version: $declared_pyver" + echo "Actual Python version: $actual_pyver" + if [ "$declared_pyver" != "$actual_pyver" ]; then + echo "Python version mismatch: declared $declared_pyver, image has $actual_pyver" + exit 1 + fi + + - name: Test with pytest + uses: ./.github/actions/docker-run + with: + uid: ${{ steps.build.outputs.unique }} + tag: ${{ matrix.name }} + env: | + CODECOV_TOKEN=${{ secrets.CODECOV_TOKEN }} + command: | + pytest \ + -k "${{ matrix.test-set }}" \ + -m "not parallel" \ + --cov \ + --cov-config=.coveragerc \ + --cov-report=xml \ + tests/ + + - name: Cleanup docker image + if: always() + uses: ./.github/actions/docker-clean + with: + uid: ${{ steps.build.outputs.unique }} + tag: ${{ matrix.name }} diff --git a/.github/workflows/pytest-gpu.yaml b/.github/workflows/pytest-gpu.yaml index 993fc53b1e..71cef40733 100644 --- a/.github/workflows/pytest-gpu.yaml +++ b/.github/workflows/pytest-gpu.yaml @@ -1,12 +1,8 @@ -# Runner information: +# Workflow information: # - OpenACC/OpenMP on NVIDIA runs on runners labeled `nvidiagpu` # - OpenMP on AMD runs on runners labeled `amdgpu` -# -# Changes vs original: -# * Respect CUDA_VISIBLE_DEVICES for NVIDIA jobs by passing it AND restricting Docker with --gpus "device=…" -# * Tag images and container names with ${{ runner.name }} to avoid cross-runner races and maximize cache reuse -# * Remove docker prune / global container deletes (we assume disk space is fine) -# * Add comments throughout +# - Respect CUDA_VISIBLE_DEVICES for NVIDIA jobs by passing it AND restricting Docker with --gpus "device=…" +# - Tag images and container names to avoid cross-runner races and maximize cache reuse name: CI-gpu @@ -37,9 +33,6 @@ jobs: - self-hosted - ${{ matrix.runner_label }} - outputs: - unique : ${{ steps.uniquetag.outputs.unique }} - strategy: fail-fast: false matrix: @@ -47,133 +40,97 @@ jobs: test_examples: ["examples/seismic/tti/tti_example.py examples/seismic/acoustic/acoustic_example.py examples/seismic/viscoacoustic/viscoacoustic_example.py examples/seismic/viscoelastic/viscoelastic_example.py examples/seismic/elastic/elastic_example.py"] include: - # -------------------- NVIDIA job -------------------- - - name: pytest-gpu-acc-nvidia - test_files: "tests/test_adjoint.py tests/test_gpu_common.py tests/test_gpu_openacc.py tests/test_operator.py::TestEstimateMemory" - base: "devitocodes/bases:nvidia-nvc12" - runner_label: nvidiagpu - test_drive_cmd: "nvidia-smi" - # Respect CUDA_VISIBLE_DEVICES and also hard-limit Docker to that device. - # NOTE: CUDA_VISIBLE_DEVICES must be set by the runner (systemd drop-in etc.). - dockerflags: >- - --init --rm -t - --name ${CONTAINER_BASENAME} - --gpus "device=${CUDA_VISIBLE_DEVICES:-all}" - - # -------------------- AMD job ----------------------- - - name: pytest-gpu-omp-amd - test_files: "tests/test_adjoint.py tests/test_gpu_common.py tests/test_gpu_openmp.py tests/test_operator.py::TestEstimateMemory" - runner_label: amdgpu - base: "devitocodes/bases:amd" - test_drive_cmd: "rocm-smi" - # Unchanged, still passes through required /dev nodes etc. - dockerflags: >- - --init --network=host - --device=/dev/kfd --device=/dev/dri - --ipc=host - --group-add video --group-add "$(getent group render | cut -d: -f3)" - --cap-add=SYS_PTRACE --security-opt seccomp=unconfined - --rm -t - --name ${CONTAINER_BASENAME} + # -------------------- NVIDIA job -------------------- + - name: pytest-gpu-acc-nvidia + test_files: "tests/test_adjoint.py tests/test_gpu_common.py tests/test_gpu_openacc.py tests/test_operator.py::TestEstimateMemory" + base: "devitocodes/bases:nvidia-nvc12" + runner_label: nvidiagpu + test_drive_cmd: "nvidia-smi" + # Respect CUDA_VISIBLE_DEVICES and also hard-limit Docker to that device. + # NOTE: CUDA_VISIBLE_DEVICES must be set by the runner (systemd drop-in etc.). + dockerflags: --gpus "device=${CUDA_VISIBLE_DEVICES:-all}" + + # -------------------- AMD job ----------------------- + - name: pytest-gpu-omp-amd + test_files: "tests/test_adjoint.py tests/test_gpu_common.py tests/test_gpu_openmp.py tests/test_operator.py::TestEstimateMemory" + runner_label: amdgpu + base: "devitocodes/bases:amd" + test_drive_cmd: "rocm-smi" + # Unchanged, still passes through required /dev nodes etc. + dockerflags: >- + --network=host + --device=/dev/kfd --device=/dev/dri + --ipc=host + --group-add video --group-add "$(getent group render | cut -d: -f3)" + --cap-add=SYS_PTRACE --security-opt seccomp=unconfined steps: - - name: Checkout devito - uses: actions/checkout@v6 - - - name: Generate unique CI tag - id: uniquetag - run: | - UNIQUE=$(echo "${GITHUB_RUN_ID}_${GITHUB_RUN_ATTEMPT}" | cksum | cut -f 1 -d " ") - echo "Unique ID: ${UNIQUE}" - echo "unique=${UNIQUE}" >> "$GITHUB_OUTPUT" - - - name: Set per-runner tags - env: - UNIQUE: ${{ steps.uniquetag.outputs.unique }} - run: | - echo "DOCKER_IMAGE=${{ matrix.name }}-${RUNNER_NAME// /_}-${UNIQUE}" >> "$GITHUB_ENV" - echo "CONTAINER_BASENAME=testrun-${{ matrix.name }}-${RUNNER_NAME// /_}-${{ github.sha }}" >> "$GITHUB_ENV" - - - name: Ensure buildx builder - run: | - docker buildx inspect "${RUNNER_NAME// /_}" >/dev/null 2>&1 || \ - docker buildx create --name "${RUNNER_NAME// /_}" --driver docker-container - docker buildx use "${RUNNER_NAME// /_}" - - - name: Build docker image - run: | - docker buildx build . \ - --builder "${RUNNER_NAME// /_}" \ - --load \ - --label ci-run="$GITHUB_RUN_ID" \ - --rm --pull \ - --file docker/Dockerfile.devito \ - --tag "${DOCKER_IMAGE}" \ - --build-arg base="${{ matrix.base }}" - - - name: Export CODECOV token - run: echo "CODECOV_TOKEN=${{ secrets.CODECOV_TOKEN }}" >> "$GITHUB_ENV" - - - name: Probe gpu - run: | - # Make sure CUDA_VISIBLE_DEVICES is at least *something* on NVIDIA - # runners; fall back to "all" so the driver probe does not fail. - if [[ "${{ matrix.runner_label }}" == "nvidiagpu" && -z "${CUDA_VISIBLE_DEVICES:-}" ]]; then - echo "CUDA_VISIBLE_DEVICES=all" >> "$GITHUB_ENV" - fi - - # Run a simple driver-probe command (nvidia-smi / rocm-smi) - docker rm -f "${CONTAINER_BASENAME}" 2>/dev/null || true - docker run ${{ matrix.dockerflags }} "${DOCKER_IMAGE}" ${{ matrix.test_drive_cmd }} - - - name: Test with pytest - env: - # Exported earlier in the job; needed inside the container for codecov - CODECOV_TOKEN: ${{ env.CODECOV_TOKEN }} - run: | - # Add Codecov’s environment variables (GITHUB_SHA, etc.) - ci_env=$(bash <(curl -s https://codecov.io/env)) - - # Run the test suite using the matrix-defined flags - docker run \ - ${{ matrix.dockerflags }} \ - "${ci_env}" \ - --env CI=true \ - --env PYTHONFAULTHANDLER=1 \ - --env DEVITO_LOGGING=DEBUG \ - --env CODECOV_TOKEN \ - "${DOCKER_IMAGE}" \ - pytest -vvv --capture=no --showlocals \ - --log-cli-level=DEBUG -o log_cli=true \ - --full-trace --durations=10 \ - --cov --cov-config=.coveragerc --cov-report=xml \ - ${{ matrix.test_files }} - - - name: Test examples - run: | - docker run \ - ${{ matrix.dockerflags }} \ - "${DOCKER_IMAGE}" \ - pytest ${{ matrix.test_examples }} - - - name: Test examples with MPI - run: | - docker run \ - ${{ matrix.dockerflags }} \ - --env DEVITO_MPI=1 \ - "${DOCKER_IMAGE}" \ - mpiexec -n 2 pytest ${{ matrix.test_examples }} - - - name: Builder & image cleanup (keep 3 days of cache) - if: always() - run: | - # Remove only the test image we built - docker rmi -f "${DOCKER_IMAGE}" || true - - # Classic image layers created in this job - docker image prune -f --filter label=ci-run="$GITHUB_RUN_ID" - - # BuildKit cache: target the per-runner builder explicitly - docker builder prune --builder "${RUNNER_NAME// /_}" \ - -f \ - --filter "until=72h" + - name: Checkout devito + uses: actions/checkout@v6 + + - id: build + name: Build docker image + uses: ./.github/actions/docker-build + with: + file: docker/Dockerfile.devito + tag: ${{ matrix.name }} + base: ${{ matrix.base }} + + - name: Probe GPU + uses: ./.github/actions/docker-run + with: + uid: ${{ steps.build.outputs.unique }} + tag: ${{ matrix.name }} + command: ${{ matrix.test_drive_cmd }} + + - name: Test with pytest + uses: ./.github/actions/docker-run + with: + uid: ${{ steps.build.outputs.unique }} + tag: ${{ matrix.name }} + args: ${{ matrix.dockerflags }} + env: | + CI=true + CODECOV_TOKEN=${{ secrets.CODECOV_TOKEN }} + DEVITO_LOGGING=DEBUG + PYTHONFAULTHANDLER=1 + command: | + pytest \ + -vvv \ + --capture=no \ + --showlocals \ + --log-cli-level=DEBUG \ + -o log_cli=true \ + --full-trace \ + --durations=10 \ + --cov \ + --cov-config=.coveragerc \ + --cov-report=xml \ + ${{ matrix.test_files }} + + - name: Test examples + uses: ./.github/actions/docker-run + with: + uid: ${{ steps.build.outputs.unique }} + tag: ${{ matrix.name }} + args: ${{ matrix.dockerflags }} + env: | + command: pytest ${{ matrix.test_examples }} + + - name: Test examples with MPI + uses: ./.github/actions/docker-run + with: + uid: ${{ steps.build.outputs.unique }} + tag: ${{ matrix.name }} + args: ${{ matrix.dockerflags }} + env: | + DEVITO_LOGGING=DEBUG + DEVITO_MPI=1 + command: mpiexec -n 2 pytest ${{ matrix.test_examples }} + + - name: Cleanup docker image + if: always() + uses: ./.github/actions/docker-clean + with: + uid: ${{ steps.build.outputs.unique }} + tag: ${{ matrix.name }} diff --git a/docker/coverage.env b/docker/coverage.env new file mode 100644 index 0000000000..f954033159 --- /dev/null +++ b/docker/coverage.env @@ -0,0 +1,23 @@ +# Generic code coverage variables +CODECOV_ENV +CODECOV_TOKEN +CODECOV_URL +CODECOV_SLUG +VCS_COMMIT_ID +VCS_BRANCH_NAME +VCS_PULL_REQUEST +VCS_SLUG +VCS_TAG +CI_BUILD_URL +CI_BUILD_ID +CI_JOB_ID + +# Github specific code coverage variables +GITHUB_ACTIONS +GITHUB_HEAD_REF +GITHUB_REF +GITHUB_REPOSITORY +GITHUB_RUN_ID +GITHUB_SERVER_URL +GITHUB_SHA +GITHUB_WORKFLOW