@@ -179,61 +179,59 @@ jobs:
179179
180180 # NVHPC compiler matrix: cpu (build+test), gpu (build-only, acc then omp)
181181 # Every release from 23.11 through 26.3 (current)
182- # Using single-CUDA tags instead of cuda_multi to fit GitHub runner disk.
183- # nvhpc -> highest bundled CUDA 12.x (from release notes)
184- - { nvhpc: '23.11', target: cpu, cuda: '12.3' }
185- - { nvhpc: '23.11', target: gpu, cuda: '12.3' }
186- - { nvhpc: '24.1', target: cpu, cuda: '12.3' }
187- - { nvhpc: '24.1', target: gpu, cuda: '12.3' }
188- - { nvhpc: '24.3', target: cpu, cuda: '12.3' }
189- - { nvhpc: '24.3', target: gpu, cuda: '12.3' }
190- - { nvhpc: '24.5', target: cpu, cuda: '12.4' }
191- - { nvhpc: '24.5', target: gpu, cuda: '12.4' }
192- - { nvhpc: '24.7', target: cpu, cuda: '12.5' }
193- - { nvhpc: '24.7', target: gpu, cuda: '12.5' }
194- - { nvhpc: '24.9', target: cpu, cuda: '12.6' }
195- - { nvhpc: '24.9', target: gpu, cuda: '12.6' }
196- - { nvhpc: '24.11', target: cpu, cuda: '12.6' }
197- - { nvhpc: '24.11', target: gpu, cuda: '12.6' }
198- - { nvhpc: '25.1', target: cpu, cuda: '12.6' }
199- - { nvhpc: '25.1', target: gpu, cuda: '12.6' }
200- - { nvhpc: '25.3', target: cpu, cuda: '12.8' }
201- - { nvhpc: '25.3', target: gpu, cuda: '12.8' }
202- - { nvhpc: '25.5', target: cpu, cuda: '12.8' }
203- - { nvhpc: '25.5', target: gpu, cuda: '12.8' }
204- - { nvhpc: '25.7', target: cpu, cuda: '12.8' }
205- - { nvhpc: '25.7', target: gpu, cuda: '12.8' }
206- - { nvhpc: '25.9', target: cpu, cuda: '12.9' }
207- - { nvhpc: '25.9', target: gpu, cuda: '12.9' }
208- - { nvhpc: '25.11', target: cpu, cuda: '12.9' }
209- - { nvhpc: '25.11', target: gpu, cuda: '12.9' }
210- - { nvhpc: '26.1', target: cpu, cuda: '12.9' }
211- - { nvhpc: '26.1', target: gpu, cuda: '12.9' }
212- - { nvhpc: '26.3', target: cpu, cuda: '12.9' }
213- - { nvhpc: '26.3', target: gpu, cuda: '12.9' }
182+ - { nvhpc: '23.11', target: cpu }
183+ - { nvhpc: '23.11', target: gpu }
184+ - { nvhpc: '24.1', target: cpu }
185+ - { nvhpc: '24.1', target: gpu }
186+ - { nvhpc: '24.3', target: cpu }
187+ - { nvhpc: '24.3', target: gpu }
188+ - { nvhpc: '24.5', target: cpu }
189+ - { nvhpc: '24.5', target: gpu }
190+ - { nvhpc: '24.7', target: cpu }
191+ - { nvhpc: '24.7', target: gpu }
192+ - { nvhpc: '24.9', target: cpu }
193+ - { nvhpc: '24.9', target: gpu }
194+ - { nvhpc: '24.11', target: cpu }
195+ - { nvhpc: '24.11', target: gpu }
196+ - { nvhpc: '25.1', target: cpu }
197+ - { nvhpc: '25.1', target: gpu }
198+ - { nvhpc: '25.3', target: cpu }
199+ - { nvhpc: '25.3', target: gpu }
200+ - { nvhpc: '25.5', target: cpu }
201+ - { nvhpc: '25.5', target: gpu }
202+ - { nvhpc: '25.7', target: cpu }
203+ - { nvhpc: '25.7', target: gpu }
204+ - { nvhpc: '25.9', target: cpu }
205+ - { nvhpc: '25.9', target: gpu }
206+ - { nvhpc: '25.11', target: cpu }
207+ - { nvhpc: '25.11', target: gpu }
208+ - { nvhpc: '26.1', target: cpu }
209+ - { nvhpc: '26.1', target: gpu }
210+ - { nvhpc: '26.3', target: cpu }
211+ - { nvhpc: '26.3', target: gpu }
214212
215213 fail-fast : false
216214 continue-on-error : true
217215 runs-on : ${{ matrix.nvhpc && 'ubuntu-22.04' || format('{0}-latest', matrix.os) }}
218- container :
219- image : ${{ matrix.nvhpc && format('nvcr.io/nvidia/nvhpc:{0}-devel-cuda{1}-ubuntu22.04', matrix.nvhpc, matrix.cuda) || '' }}
220- options : ${{ matrix.nvhpc && '--security-opt seccomp=unconfined' || '' }}
221216 env :
222- CC : ${{ matrix.nvhpc && 'nvc' || '' }}
223- CXX : ${{ matrix.nvhpc && 'nvc++' || '' }}
224- FC : ${{ matrix.nvhpc && 'nvfortran' || '' }}
225- OMPI_ALLOW_RUN_AS_ROOT : ${{ matrix.nvhpc && '1' || '' }}
226- OMPI_ALLOW_RUN_AS_ROOT_CONFIRM : ${{ matrix.nvhpc && '1' || '' }}
227- PMIX_MCA_gds : ${{ matrix.nvhpc && 'hash' || '' }}
228- OMPI_MCA_hwloc_base_binding_policy : ${{ matrix.nvhpc && 'none' || '' }}
229- FFLAGS : ${{ matrix.nvhpc && '-tp=px -Kieee -noswitcherror' || '' }}
230- CFLAGS : ${{ matrix.nvhpc && '-tp=px' || '' }}
231- CXXFLAGS : ${{ matrix.nvhpc && '-tp=px' || '' }}
217+ # Image tag for NVHPC jobs; empty for non-NVHPC jobs.
218+ NVHPC_IMAGE : ${{ matrix.nvhpc && format('nvcr.io/nvidia/nvhpc:{0}-devel-cuda_multi-ubuntu22.04', matrix.nvhpc) || '' }}
232219
233220 steps :
234- - name : Git safe directory
221+ # ── NVHPC: free disk before pulling the ~25-30 GB cuda_multi image ──
222+ - name : Free disk space
235223 if : matrix.nvhpc
236- run : git config --global --add safe.directory /__w/MFC/MFC
224+ run : |
225+ echo "=== Disk before cleanup ==="
226+ df -h /
227+ sudo rm -rf /usr/share/dotnet /usr/local/lib/android \
228+ /opt/ghc /usr/local/share/boost /opt/hostedtoolcache \
229+ /usr/local/graalvm /usr/local/.ghcup \
230+ /usr/local/share/chromium /usr/local/lib/node_modules
231+ sudo docker image prune -af
232+ sudo apt-get clean
233+ echo "=== Disk after cleanup ==="
234+ df -h /
237235
238236 - name : Clone
239237 uses : actions/checkout@v4
@@ -276,6 +274,62 @@ jobs:
276274 echo "Coverage cache: none available — full test suite will run"
277275 fi
278276
277+ # ── NVHPC: pull image and start a long-lived container ──────────────
278+ # Replaces the container: directive so we can free disk space first.
279+ # Uses "docker run -d ... sleep infinity" + "docker exec" to preserve
280+ # installed packages and env vars across steps.
281+ - name : Pull NVHPC container
282+ if : matrix.nvhpc
283+ run : docker pull "$NVHPC_IMAGE"
284+
285+ - name : Start NVHPC container
286+ if : matrix.nvhpc
287+ run : |
288+ docker run -d --name nvhpc \
289+ --security-opt seccomp=unconfined \
290+ -v "${{ github.workspace }}:/workspace" \
291+ -w /workspace \
292+ -e CC=nvc \
293+ -e CXX=nvc++ \
294+ -e FC=nvfortran \
295+ -e OMPI_ALLOW_RUN_AS_ROOT=1 \
296+ -e OMPI_ALLOW_RUN_AS_ROOT_CONFIRM=1 \
297+ -e PMIX_MCA_gds=hash \
298+ -e OMPI_MCA_hwloc_base_binding_policy=none \
299+ -e "FFLAGS=-tp=px -Kieee -noswitcherror" \
300+ -e CFLAGS=-tp=px \
301+ -e CXXFLAGS=-tp=px \
302+ "$NVHPC_IMAGE" sleep infinity
303+
304+ - name : Setup NVHPC
305+ if : matrix.nvhpc
306+ run : |
307+ docker exec nvhpc bash -c '
308+ set -e
309+ apt-get update -y
310+ apt-get install -y cmake python3 python3-venv python3-pip \
311+ libfftw3-dev libhdf5-dev hdf5-tools git
312+
313+ # Set up NVHPC HPC-X MPI runtime paths
314+ HPCX_DIR=$(dirname "$(find /opt/nvidia/hpc_sdk -path "*/hpcx/hpcx-*/ompi/bin/mpirun" | head -1)")/../..
315+ MPI_LIB=$(mpifort --showme:link | grep -oP "(?<=-L)\S+" | head -1)
316+
317+ # Persist env vars for subsequent docker exec calls
318+ cat > /etc/nvhpc-env.sh <<EOF
319+ export LD_LIBRARY_PATH=${MPI_LIB}:${HPCX_DIR}/ucx/lib:${HPCX_DIR}/ucc/lib:\$LD_LIBRARY_PATH
320+ export OMPI_MCA_rmaps_base_oversubscribe=1
321+ EOF
322+
323+ # Debug: confirm compiler flags are set
324+ echo "=== NVHPC Environment ==="
325+ echo "FFLAGS=$FFLAGS"
326+ echo "CFLAGS=$CFLAGS"
327+ echo "CXXFLAGS=$CXXFLAGS"
328+ nvfortran --version
329+ cat /proc/cpuinfo | grep "model name" | head -1
330+ '
331+
332+ # ── Standard (non-NVHPC) setup ─────────────────────────────────────
279333 - name : Setup MacOS
280334 if : matrix.os == 'macos' && !matrix.nvhpc
281335 run : |
@@ -315,30 +369,7 @@ jobs:
315369 echo "MPICC=mpiicx" >> $GITHUB_ENV
316370 echo "MPICXX=mpiicpx" >> $GITHUB_ENV
317371
318- # --- NVHPC container setup ---
319- - name : Setup NVHPC
320- if : matrix.nvhpc
321- run : |
322- apt-get update -y
323- apt-get install -y cmake python3 python3-venv python3-pip \
324- libfftw3-dev libhdf5-dev hdf5-tools git
325- # Set up NVHPC HPC-X MPI runtime paths
326- HPCX_DIR=$(dirname "$(find /opt/nvidia/hpc_sdk -path "*/hpcx/hpcx-*/ompi/bin/mpirun" | head -1)")/../..
327- MPI_LIB=$(mpifort --showme:link | grep -oP '(?<=-L)\S+' | head -1)
328- echo "LD_LIBRARY_PATH=${MPI_LIB}:${HPCX_DIR}/ucx/lib:${HPCX_DIR}/ucc/lib:${LD_LIBRARY_PATH}" >> $GITHUB_ENV
329- # Container MPI fixes: PMIx shared-memory, hwloc binding
330- echo "PMIX_MCA_gds=hash" >> $GITHUB_ENV
331- echo "OMPI_MCA_hwloc_base_binding_policy=none" >> $GITHUB_ENV
332- echo "OMPI_MCA_rmaps_base_oversubscribe=1" >> $GITHUB_ENV
333- # Debug: confirm compiler flags are set
334- echo "=== NVHPC Environment ==="
335- echo "FFLAGS=$FFLAGS"
336- echo "CFLAGS=$CFLAGS"
337- echo "CXXFLAGS=$CXXFLAGS"
338- nvfortran --version
339- cat /proc/cpuinfo | grep "model name" | head -1
340-
341- # --- Standard build + test ---
372+ # ── Standard build + test ───────────────────────────────────────────
342373 - name : Build
343374 if : ' !matrix.nvhpc'
344375 run : |
@@ -356,22 +387,37 @@ jobs:
356387 TEST_PCT : ${{ matrix.debug == 'reldebug' && '-% 20' || '' }}
357388 ONLY_CHANGES : ${{ github.event_name == 'pull_request' && '--only-changes' || '' }}
358389
359- # --- NVHPC build + test ---
390+ # ── NVHPC build + test (via docker exec into long-lived container) ──
360391 - name : Build (NVHPC)
361392 if : matrix.nvhpc && matrix.target == 'cpu'
362- run : /bin/bash mfc.sh test -v --dry-run -j $(nproc) --test-all
393+ run : |
394+ docker exec nvhpc bash -c '
395+ source /etc/nvhpc-env.sh
396+ /bin/bash mfc.sh test -v --dry-run -j $(nproc) --test-all
397+ '
363398
364399 - name : Build (NVHPC GPU)
365400 if : matrix.nvhpc && matrix.target == 'gpu'
366- run : |
367- /bin/bash mfc.sh test -v --dry-run -j 2 --test-all --gpu acc
368- /bin/bash mfc.sh test -v --dry-run -j 2 --test-all --gpu mp
401+ run : |
402+ docker exec nvhpc bash -c '
403+ source /etc/nvhpc-env.sh
404+ /bin/bash mfc.sh test -v --dry-run -j 2 --test-all --gpu acc
405+ /bin/bash mfc.sh test -v --dry-run -j 2 --test-all --gpu mp
406+ '
369407
370408 - name : Test (NVHPC)
371409 if : matrix.nvhpc && matrix.target == 'cpu'
372- run : |
373- ulimit -s unlimited || ulimit -s 65536 || true
374- /bin/bash mfc.sh test -v --max-attempts 3 -j $(nproc) --test-all
410+ run : |
411+ docker exec nvhpc bash -c '
412+ source /etc/nvhpc-env.sh
413+ ulimit -s unlimited || ulimit -s 65536 || true
414+ /bin/bash mfc.sh test -v --max-attempts 3 -j $(nproc) --test-all
415+ '
416+
417+ # ── Cleanup ─────────────────────────────────────────────────────────
418+ - name : Stop NVHPC container
419+ if : always() && matrix.nvhpc
420+ run : docker rm -f nvhpc || true
375421
376422 self :
377423 name : " ${{ matrix.cluster_name }} (${{ matrix.device }}${{ matrix.interface != 'none' && format('-{0}', matrix.interface) || '' }}${{ matrix.shard != '' && format(' [{0}]', matrix.shard) || '' }})"
0 commit comments