diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml index 42e65f3c1..efcfcde4e 100644 --- a/.github/workflows/continuous.yml +++ b/.github/workflows/continuous.yml @@ -59,11 +59,6 @@ jobs: choco install ccache "CACHE_PATH=${env:LOCALAPPDATA}\ccache" | Out-File -FilePath $env:GITHUB_ENV -Append - # Install Ninja (only needed on Windows) - - name: Install Ninja - if: runner.os == 'Windows' - uses: seanmiddleditch/gha-setup-ninja@master - - name: Setup MSVC (Windows) if: runner.os == 'Windows' uses: ilammy/msvc-dev-cmd@v1 diff --git a/.github/workflows/cuda.yml b/.github/workflows/cuda.yml index c1653b1e8..9eedbdbd5 100644 --- a/.github/workflows/cuda.yml +++ b/.github/workflows/cuda.yml @@ -27,33 +27,81 @@ env: jobs: Build: - name: CUDA (${{ matrix.config }}) - runs-on: ubuntu-latest + name: ${{ matrix.name }} CUDA (${{ matrix.config }}) + runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: - config: - - Debug - - Release + os: [ubuntu-latest, windows-latest] + config: [Debug, Release] + exclude: + # The Windows toolkit install can't run in parallel jobs, so Windows + # only builds Debug. + - os: windows-latest + config: Release + include: + - os: ubuntu-latest + name: Linux + - os: windows-latest + name: Windows + # Windows splits the toolkit into finer components than Linux and an + # invalid component name aborts the whole install, so name exactly + # what the build needs (per the Windows installer subpackage list): + # nvcc - compiler front-end (nvcc, cudafe++, ptxas, nvlink) + # nvvm - device compiler backend (cicc); nvcc alone omits it + # cudart - cuda_runtime.h + runtime library + # crt - crt/host_config.h + # thrust - Thrust, and the CUB/libcudacxx headers it bundles + # ("cccl"/"cub" are not valid Windows installer subpackage names.) + cuda_subpackages: '["nvcc", "nvvm", "cudart", "crt", "thrust"]' steps: - name: Checkout repository uses: actions/checkout@v6 with: fetch-depth: 10 - - name: Dependencies + - name: Dependencies (Linux) + if: runner.os == 'Linux' run: | sudo apt-get install ccache echo 'CACHE_PATH=~/.cache/ccache' >> "$GITHUB_ENV" + - name: Dependencies (Windows) + if: runner.os == 'Windows' + run: | + choco install ccache + "CACHE_PATH=${env:LOCALAPPDATA}\ccache" | Out-File -FilePath $env:GITHUB_ENV -Append + # CUDA and a simulated GPU: the runners have none, so PantheonSim runs the - # tests' kernels on the CPU. It checks results, not performance. - - name: cuda-toolkit and simulated GPU + # tests' kernels on the CPU. It checks results, not performance. It only + # supports Linux, so Windows installs the toolkit alone and only builds. + - name: Install CUDA Toolkit and simulated GPU (Linux) + if: runner.os == 'Linux' uses: pantheongpu/setup-pantheonsim@052a0ac31bf6ec72a471d51aae29b7cbd090c6bf # v0.1.1 with: gpu: nvidia/t4 cuda-toolkit: '12.8' + # Install CUDA before msvc-dev-cmd so the toolkit's bin dir lands on PATH + # before msvc-dev-cmd snapshots PATH into GITHUB_ENV for later steps. + # (check_language(CUDA) still does not reliably autodetect nvcc on this + # runner even with it on PATH, so the Windows configure also passes + # -DCMAKE_CUDA_COMPILER explicitly.) We use CUDA 13 here and 12 on Linux, + # so CI compiles against both CCCL 2 and CCCL 3. + - name: Install CUDA Toolkit (Windows) + if: runner.os == 'Windows' + uses: Jimver/cuda-toolkit@v0.2.35 + with: + cuda: '13.2.0' + sub-packages: ${{ matrix.cuda_subpackages }} + method: 'network' + + - name: Setup MSVC (Windows) + if: runner.os == 'Windows' + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: x64 + - name: Get number of CPU cores uses: SimenB/github-actions-cpu-cores@v2 id: cpu-cores @@ -61,6 +109,7 @@ jobs: # On Linux, explicitly build for x86-64-v3 instead of -march=native. This # avoids issues with ccache restoring from a runner with a different ISA. - name: Check x86-64-v3 support + if: runner.os == 'Linux' run: | for f in avx2 bmi1 bmi2 f16c fma abm movbe xsave; do grep -qw "$f" /proc/cpuinfo || { echo "::error::Runner CPU lacks $f, which x86-64-v3 requires"; exit 1; } @@ -78,6 +127,7 @@ jobs: key: cuda-${{ runner.os }}-${{ matrix.config }}-cache - name: Prepare ccache + shell: bash run: | ccache --max-size=1.0G ccache -V && ccache --show-config @@ -88,7 +138,8 @@ jobs: # never reads it: assert and Catch2 messages carry __FILE__ and __LINE__. # The CUDA Debug flags are emptied instead of set to -O0, which nvcc would # also apply to the device code. - - name: Configure + - name: Configure (Linux) + if: runner.os == 'Linux' run: | mkdir -p build cd build @@ -105,7 +156,31 @@ jobs: -DCMAKE_BUILD_TYPE=${{ matrix.config }} \ -DCMAKE_CUDA_RUNTIME_LIBRARY=Shared + # MSVC's default Debug flags include /Zi, which ccache cannot cache, so we + # drop it the same way the Linux configure drops -g. + - name: Configure (Windows) + if: runner.os == 'Windows' + shell: cmd + run: | + cmake -G Ninja ^ + -DIPC_TOOLKIT_WITH_CUDA=ON ^ + -DCMAKE_C_FLAGS_DEBUG="/Od /Ob0 /RTC1" ^ + -DCMAKE_CXX_FLAGS_DEBUG="/Od /Ob0 /RTC1" ^ + -DCMAKE_CUDA_FLAGS_DEBUG= ^ + -DCMAKE_CUDA_ARCHITECTURES=75 ^ + -DSCALABLE_CCD_CUDA_ARCHITECTURES=75 ^ + -DIPC_TOOLKIT_BUILD_TESTS=ON ^ + -DIPC_TOOLKIT_BUILD_PYTHON=ON ^ + -DCMAKE_CUDA_COMPILER="%CUDA_PATH%\bin\nvcc.exe" ^ + -DCMAKE_BUILD_TYPE=${{ matrix.config }} ^ + -B build ^ + -S . + + # Use bash on every runner. Windows' default pwsh reports only the last + # native command's exit code, so a failed build followed by a successful + # `ccache --show-stats` would pass the step. - name: Build + shell: bash run: | cmake --build build -j ${{ steps.cpu-cores.outputs.count }} ccache --show-stats @@ -113,4 +188,5 @@ jobs: # The GPU unit tests, minus the CCD and STQ ones on the cloth and puffer # ball meshes, which take several minutes each on a simulated GPU. - name: Tests + if: runner.os == 'Linux' run: build/tests/ipc_toolkit_tests "[gpu]~[ccd]~[.],[cuda]~[stq]~[.]" diff --git a/cmake/ipc_toolkit/ipc_toolkit_warnings.cmake b/cmake/ipc_toolkit/ipc_toolkit_warnings.cmake index ff799263b..b95e87f10 100644 --- a/cmake/ipc_toolkit/ipc_toolkit_warnings.cmake +++ b/cmake/ipc_toolkit/ipc_toolkit_warnings.cmake @@ -9,14 +9,10 @@ endif() # Flags above don't make sense for MSVC if(MSVC) - set(IPC_TOOLKIT_WARNING_FLAGS - /W4 # High warning level (MSVC equivalent of -Wall -Wextra; /Wall is - # unusably noisy, enabling off-by-default warnings like C4711/C4710/ - # C4514/C4820/C5045) - /MP # Multi-processor compilation - # Silence /W4 warnings that have no counterpart in our GCC/Clang flag set - # (-Wall -Wextra -Wpedantic, with -Wconversion intentionally off), so the - # MSVC output matches the other compilers: + # Silence /W4 warnings that have no counterpart in our GCC/Clang flag set + # (-Wall -Wextra -Wpedantic, with -Wconversion intentionally off), so the + # MSVC output matches the other compilers. The CUDA host pass reuses these. + set(IPC_TOOLKIT_MSVC_DISABLED_WARNINGS /wd4250 # 'inherits via dominance' (benign; from virtual inheritance) /wd4244 # conversion, possible loss of data (GCC: -Wconversion, off) /wd4267 # size_t -> smaller conversion (GCC: -Wconversion, off) @@ -27,6 +23,13 @@ if(MSVC) # params they use) are compiled out, and the collision-stencil # virtual overrides legitimately ignore some params. ) + set(IPC_TOOLKIT_WARNING_FLAGS + /W4 # High warning level (MSVC equivalent of -Wall -Wextra; /Wall is + # unusably noisy, enabling off-by-default warnings like C4711/C4710/ + # C4514/C4820/C5045) + /MP # Multi-processor compilation + ${IPC_TOOLKIT_MSVC_DISABLED_WARNINGS} + ) else() set(IPC_TOOLKIT_WARNING_FLAGS -Wall @@ -226,6 +229,14 @@ if(IPC_TOOLKIT_WITH_CUDA AND NOT MSVC) ) ipc_toolkit_filter_nvcc_flags(IPC_TOOLKIT_NVCC_HOST_WARNING_FLAGS) target_compile_options(ipc_toolkit_warnings INTERFACE ${IPC_TOOLKIT_NVCC_HOST_WARNING_FLAGS}) +elseif(IPC_TOOLKIT_WITH_CUDA) + # With an MSVC host, we only forward the disabled warnings. nvcc's + # `-Werror all-warnings` (below) also makes the host compiler treat its + # warnings as errors, so without these the host pass fails on things the C++ + # build already silences, like C4068 for our `#pragma GCC` directives. + set(IPC_TOOLKIT_NVCC_HOST_WARNING_FLAGS ${IPC_TOOLKIT_MSVC_DISABLED_WARNINGS}) + ipc_toolkit_filter_nvcc_flags(IPC_TOOLKIT_NVCC_HOST_WARNING_FLAGS) + target_compile_options(ipc_toolkit_warnings INTERFACE ${IPC_TOOLKIT_NVCC_HOST_WARNING_FLAGS}) endif() # The device pass has no -Wall; nvcc's own diagnostics are few, and these are @@ -245,4 +256,13 @@ if(IPC_TOOLKIT_WITH_CUDA) target_compile_options(ipc_toolkit_warnings INTERFACE "$<$,$>:SHELL:-Werror all-warnings>" "$<$,$>:SHELL:-Werror cross-execution-space-call>") + + # With an MSVC host, the front end flags two warnings inside spdlog's bundled + # fmt (#128 "loop is not reachable" and #2417 "constexpr constructor calls + # non-constexpr function"), even though it is an -isystem include. Under + # all-warnings these fail the build, and we can't fix third-party code, so we + # suppress them for MSVC hosts only. This is safe because the Linux build + # still turns both into errors, so our own code stays covered. + target_compile_options(ipc_toolkit_warnings INTERFACE + "$<$,$,$>:-diag-suppress=128,2417>") endif()