diff --git a/.github/actions/compute-matrix/compute-matrix.sh b/.github/actions/compute-matrix/compute-matrix.sh index cd3946f1..3c1471bc 100755 --- a/.github/actions/compute-matrix/compute-matrix.sh +++ b/.github/actions/compute-matrix/compute-matrix.sh @@ -18,6 +18,20 @@ extract_matrix() { local per_cuda_compiler_matrix="$(echo "$nvcc_full_matrix" | jq -cr ' group_by(.cuda + .compiler.name) | map({(.[0].cuda + "-" + .[0].compiler.name): .}) | add')" write_output "PER_CUDA_COMPILER_MATRIX" "$per_cuda_compiler_matrix" write_output "PER_CUDA_COMPILER_KEYS" "$(echo "$per_cuda_compiler_matrix" | jq -r 'keys | @json')" + + local windows_matrix="$(echo "$matrix" | jq -cr ' + (.windows // []) + | map({ + cuda: .cuda, + host: (.host // (.compiler.name + (.compiler.version | tostring))), + cpu: (.cpu // "amd64"), + runner: (.runner // ("windows-" + (.cpu // "amd64") + "-cpu16")), + std: ((.std // "17") | tostring), + arch: (.arch // ""), + image: (.image // "") + }) + ')" + write_output "WINDOWS_MATRIX" "$windows_matrix" } main() { diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml new file mode 100644 index 00000000..777d2665 --- /dev/null +++ b/.github/workflows/build-windows.yml @@ -0,0 +1,170 @@ +name: build windows + +defaults: + run: + shell: powershell + +on: + workflow_call: + inputs: + cuda: + type: string + required: false + default: "13.0" + host: + type: string + required: false + default: "cl14.44" + devcontainer_version: + type: string + required: false + default: "25.12" + image: + type: string + required: false + default: "" + runner: + type: string + required: false + default: "windows-amd64-cpu16" + std: + type: string + required: false + default: "17" + arch: + type: string + required: false + default: "" + workflow_dispatch: + inputs: + cuda: + description: "CUDA Toolkit version" + type: string + required: false + default: "13.0" + host: + description: "Host compiler tag" + type: string + required: false + default: "cl14.44" + devcontainer_version: + description: "RAPIDS devcontainer version" + type: string + required: false + default: "25.12" + image: + description: "Windows devcontainer image override" + type: string + required: false + default: "" + runner: + description: "Windows runner" + type: string + required: false + default: "windows-amd64-cpu16" + std: + description: "C++/CUDA standard" + type: choice + options: ["17", "20"] + required: false + default: "17" + arch: + description: "CMAKE_CUDA_ARCHITECTURES override" + type: string + required: false + default: "" + +permissions: + contents: read + +jobs: + build-windows: + name: Build Windows CUDA${{ inputs.cuda }} ${{ inputs.host }} C++${{ inputs.std }} + runs-on: ${{ github.repository == 'NVIDIA/nvbench' && inputs.runner || 'windows-latest' }} + permissions: + id-token: write + contents: read + env: + WINDOWS_CI_IMAGE: ${{ inputs.image != '' && inputs.image || format('rapidsai/devcontainers:{0}-cuda{1}-{2}', inputs.devcontainer_version, inputs.cuda, inputs.host) }} + SCCACHE_BUCKET: rapids-sccache-devs + SCCACHE_REGION: us-east-2 + SCCACHE_IDLE_TIMEOUT: "0" + SCCACHE_S3_USE_SSL: "true" + SCCACHE_S3_NO_CREDENTIALS: "false" + SCCACHE_S3_USE_PREPROCESSOR_CACHE_MODE: "true" + SCCACHE_S3_PREPROCESSOR_CACHE_KEY_PREFIX: nvbench-preprocessor-cache + steps: + - name: Checkout repo + uses: actions/checkout@v4 + with: + fetch-depth: 0 + fetch-tags: true + persist-credentials: false + + - name: Add NVCC problem matcher + run: | + echo "::add-matcher::.github/problem-matchers/problem-matcher.json" + + - name: Get AWS credentials for sccache bucket + if: ${{ github.repository == 'NVIDIA/nvbench' }} + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: arn:aws:iam::279114543810:role/gha-oidc-NVIDIA + aws-region: us-east-2 + role-duration-seconds: 43200 + + - name: Fetch Windows devcontainer image + run: | + docker pull "$env:WINDOWS_CI_IMAGE" + + - name: Build NVBench + env: + NVBENCH_WINDOWS_STD: ${{ inputs.std }} + NVBENCH_WINDOWS_ARCH: ${{ inputs.arch }} + run: | + $ErrorActionPreference = "Stop" + + $hostRepo = "${{ github.workspace }}".Replace('\', '/') + $containerRepo = "C:/nvbench" + $script = Join-Path $env:RUNNER_TEMP "nvbench-windows-ci.ps1" + + @" + `$ErrorActionPreference = 'Stop' + git config --global --add safe.directory '$containerRepo' + & '$containerRepo/ci/windows/build_nvbench.ps1' -std '$env:NVBENCH_WINDOWS_STD' -arch '$env:NVBENCH_WINDOWS_ARCH' + exit `$LASTEXITCODE + "@ | Set-Content -Path $script -Encoding UTF8 + + $containerScript = "$containerRepo/nvbench-windows-ci.ps1" + Copy-Item $script "${{ github.workspace }}\nvbench-windows-ci.ps1" + + $dockerArgs = @( + "run", "--rm", + "--mount", "type=bind,source=$hostRepo,target=$containerRepo", + "--workdir", $containerRepo, + "--isolation=process", + "--env", "AWS_ACCESS_KEY_ID=$env:AWS_ACCESS_KEY_ID", + "--env", "AWS_SECRET_ACCESS_KEY=$env:AWS_SECRET_ACCESS_KEY", + "--env", "AWS_SESSION_TOKEN=$env:AWS_SESSION_TOKEN", + "--env", "CI=true", + "--env", "GITHUB_ACTIONS=$env:GITHUB_ACTIONS", + "--env", "GITHUB_REF_NAME=$env:GITHUB_REF_NAME", + "--env", "GITHUB_REPOSITORY=$env:GITHUB_REPOSITORY", + "--env", "GITHUB_RUN_ID=$env:GITHUB_RUN_ID", + "--env", "GITHUB_SHA=$env:GITHUB_SHA", + "--env", "SCCACHE_BUCKET=$env:SCCACHE_BUCKET", + "--env", "SCCACHE_IDLE_TIMEOUT=$env:SCCACHE_IDLE_TIMEOUT", + "--env", "SCCACHE_REGION=$env:SCCACHE_REGION", + "--env", "SCCACHE_S3_NO_CREDENTIALS=$env:SCCACHE_S3_NO_CREDENTIALS", + "--env", "SCCACHE_S3_PREPROCESSOR_CACHE_KEY_PREFIX=$env:SCCACHE_S3_PREPROCESSOR_CACHE_KEY_PREFIX", + "--env", "SCCACHE_S3_USE_PREPROCESSOR_CACHE_MODE=$env:SCCACHE_S3_USE_PREPROCESSOR_CACHE_MODE", + "--env", "SCCACHE_S3_USE_SSL=$env:SCCACHE_S3_USE_SSL", + "$env:WINDOWS_CI_IMAGE", + "powershell", "-NoLogo", "-NoProfile", "-ExecutionPolicy", "Bypass", + "-File", $containerScript + ) + + docker @dockerArgs + if ($LASTEXITCODE -ne 0) { + exit $LASTEXITCODE + } diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index c42cda01..7ea85397 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -42,6 +42,7 @@ jobs: DEVCONTAINER_VERSION: ${{steps.set-outputs.outputs.DEVCONTAINER_VERSION}} PER_CUDA_COMPILER_MATRIX: ${{steps.set-outputs.outputs.PER_CUDA_COMPILER_MATRIX}} PER_CUDA_COMPILER_KEYS: ${{steps.set-outputs.outputs.PER_CUDA_COMPILER_KEYS}} + WINDOWS_MATRIX: ${{steps.set-outputs.outputs.WINDOWS_MATRIX}} base_sha: ${{ steps.export-pr-info.outputs.base_sha }} pr_number: ${{ steps.export-pr-info.outputs.pr_number }} steps: @@ -76,6 +77,28 @@ jobs: per_cuda_compiler_matrix: ${{ toJSON(fromJSON(needs.compute-matrix.outputs.PER_CUDA_COMPILER_MATRIX)[ matrix.cuda_host_combination ]) }} devcontainer_version: ${{ needs.compute-matrix.outputs.DEVCONTAINER_VERSION }} + nvbench-windows: + name: NVBench Windows CUDA${{ matrix.config.cuda }} ${{ matrix.config.host }} C++${{ matrix.config.std }} + # TODO: Re-enable after https://github.com/NVIDIA/nvbench/pull/354 fixes the Windows build. + if: false + permissions: + id-token: write + contents: read + needs: compute-matrix + uses: ./.github/workflows/build-windows.yml + strategy: + fail-fast: false + matrix: + config: ${{ fromJSON(needs.compute-matrix.outputs.WINDOWS_MATRIX) }} + with: + cuda: ${{ matrix.config.cuda }} + host: ${{ matrix.config.host }} + runner: ${{ matrix.config.runner }} + std: ${{ matrix.config.std }} + arch: ${{ matrix.config.arch }} + image: ${{ matrix.config.image }} + devcontainer_version: ${{ needs.compute-matrix.outputs.DEVCONTAINER_VERSION }} + python-wheels: name: Python Wheels permissions: @@ -103,6 +126,7 @@ jobs: if: ${{ always() }} # need to use always() instead of !cancelled() because skipped jobs count as success needs: - nvbench + - nvbench-windows - python-wheels - verify-devcontainers steps: diff --git a/ci/matrix.yaml b/ci/matrix.yaml index d8cccb41..8b1d0db0 100644 --- a/ci/matrix.yaml +++ b/ci/matrix.yaml @@ -24,6 +24,9 @@ llvm18: &llvm18 { name: 'llvm', version: '18', exe: 'clang++' } llvm19: &llvm19 { name: 'llvm', version: '19', exe: 'clang++' } llvm20: &llvm20 { name: 'llvm', version: '20', exe: 'clang++' } +# MSVC compiler configurations +msvc2022: &msvc2022 { name: 'cl', version: '14.44', exe: 'cl' } + # Each environment below will generate a unique build/test job # See the "compute-matrix" job in the workflow for how this is parsed and used # cuda: The CUDA Toolkit version @@ -68,6 +71,8 @@ pull_request: - {cuda: *cuda_curr_max, compiler: *llvm18, cpu: 'amd64'} - {cuda: *cuda_curr_max, compiler: *llvm19, cpu: 'amd64'} - {cuda: *cuda_curr_max, compiler: *llvm20, cpu: 'amd64'} + windows: + - {cuda: *cuda_curr_max, compiler: *msvc2022, cpu: 'amd64', std: '17'} # Python wheel builds python_wheels: diff --git a/ci/windows/build_common.psm1 b/ci/windows/build_common.psm1 new file mode 100644 index 00000000..f2a32655 --- /dev/null +++ b/ci/windows/build_common.psm1 @@ -0,0 +1,181 @@ +Param( + [Parameter(Mandatory = $false)] + [Alias("std")] + [ValidateNotNullOrEmpty()] + [ValidateSet(17, 20)] + [int]$CXX_STANDARD = 17, + + [Parameter(Mandatory = $false)] + [Alias("arch")] + [string]$CUDA_ARCH = "", + + [Parameter(Mandatory = $false)] + [Alias("cmake-options")] + [string]$CMAKE_OPTIONS = "" +) + +$ErrorActionPreference = "Stop" + +function Split-CMakeOptions { + Param( + [Parameter(Mandatory = $false)] + [string]$Options = "" + ) + + if (-not $Options) { + return @() + } + + return @($Options -split '\s+' | Where-Object { $_ }) +} + +function Invoke-OptionalSccache { + Param( + [Parameter(Mandatory = $false)] + [string[]]$Arguments = @() + ) + + if (-not (Get-Command sccache -ErrorAction SilentlyContinue)) { + return + } + + & sccache @Arguments + if ($LASTEXITCODE -ne 0) { + Write-Warning "sccache $($Arguments -join ' ') failed with exit code $LASTEXITCODE" + } +} + +# Use the full cl.exe path. CMake otherwise may resolve CMAKE_CXX_COMPILER to a +# full path while leaving CMAKE_CUDA_HOST_COMPILER as "cl", which fails NVBench's +# host/compiler consistency check. +$script:HOST_COMPILER = (Get-Command "cl.exe").Source -replace '\\', '/' +$script:CUDA_COMPILER = (Get-Command "nvcc.exe").Source -replace '\\', '/' +$script:PARALLEL_LEVEL = if ($env:NUMBER_OF_PROCESSORS) { $env:NUMBER_OF_PROCESSORS } else { 1 } + +$script:GLOBAL_CMAKE_OPTIONS = @(Split-CMakeOptions $CMAKE_OPTIONS) +if ($CUDA_ARCH) { + $script:GLOBAL_CMAKE_OPTIONS += "-DCMAKE_CUDA_ARCHITECTURES=$CUDA_ARCH" +} + +if (-not $env:CCCL_BUILD_INFIX) { + $env:CCCL_BUILD_INFIX = "" +} + +$env:CMAKE_BUILD_PARALLEL_LEVEL = $script:PARALLEL_LEVEL +$env:CTEST_PARALLEL_LEVEL = 1 +$env:CMAKE_GENERATOR = "Ninja" +$env:CXX = $script:HOST_COMPILER +$env:CUDACXX = $script:CUDA_COMPILER +$env:CUDAHOSTCXX = $script:HOST_COMPILER + +Invoke-OptionalSccache -Arguments @("--start-server") + +function Print-EnvironmentDetails { + Write-Host "========================================" + Write-Host "Begin build" + Write-Host "pwd=$pwd" + Write-Host "CXX_STANDARD=$CXX_STANDARD" + Write-Host "CXX=$env:CXX" + Write-Host "CUDACXX=$env:CUDACXX" + Write-Host "CUDAHOSTCXX=$env:CUDAHOSTCXX" + Write-Host "CMAKE_BUILD_PARALLEL_LEVEL=$env:CMAKE_BUILD_PARALLEL_LEVEL" + Write-Host "CTEST_PARALLEL_LEVEL=$env:CTEST_PARALLEL_LEVEL" + Write-Host "CCCL_BUILD_INFIX=$env:CCCL_BUILD_INFIX" + Write-Host "GLOBAL_CMAKE_OPTIONS=$($script:GLOBAL_CMAKE_OPTIONS -join ' ')" + Write-Host "Current commit is:" + git log -1 --format=short + Write-Host "========================================" + + cmake --version + ctest --version + ninja --version + cl.exe /? + nvcc --version + Invoke-OptionalSccache -Arguments @("--version") +} + +function Invoke-NativeCommand { + Param( + [Parameter(Mandatory = $true)] + [string]$Step, + + [Parameter(Mandatory = $true)] + [string]$Command, + + [Parameter(Mandatory = $false)] + [string[]]$Arguments = @() + ) + + Write-Host ">>> $Step" + Write-Host "$Command $($Arguments -join ' ')" + & $Command @Arguments + if ($LASTEXITCODE -ne 0) { + throw "$Step failed with exit code $LASTEXITCODE" + } +} + +function Configure-Preset { + Param( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [string]$BUILD_NAME, + + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [string]$PRESET, + + [Parameter(Mandatory = $false)] + [string[]]$LOCAL_CMAKE_OPTIONS = @() + ) + + Push-Location ".." + try { + $args = @("--preset", $PRESET, "--log-level=VERBOSE") + $args += $LOCAL_CMAKE_OPTIONS + $args += $script:GLOBAL_CMAKE_OPTIONS + Invoke-NativeCommand "$BUILD_NAME configure" "cmake" $args + } finally { + Pop-Location + } +} + +function Build-Preset { + Param( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [string]$BUILD_NAME, + + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [string]$PRESET + ) + + Push-Location ".." + try { + Invoke-OptionalSccache -Arguments @("-z") + Invoke-NativeCommand "$BUILD_NAME build" "cmake" @("--build", "--preset=$PRESET", "-v") + Invoke-OptionalSccache -Arguments @("--show-adv-stats") + } finally { + Pop-Location + } +} + +function Configure-And-Build-Preset { + Param( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [string]$BUILD_NAME, + + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [string]$PRESET, + + [Parameter(Mandatory = $false)] + [string[]]$LOCAL_CMAKE_OPTIONS = @() + ) + + Configure-Preset $BUILD_NAME $PRESET $LOCAL_CMAKE_OPTIONS + Build-Preset $BUILD_NAME $PRESET +} + +Export-ModuleMember -Function Print-EnvironmentDetails, Configure-Preset, Build-Preset, Configure-And-Build-Preset diff --git a/ci/windows/build_nvbench.ps1 b/ci/windows/build_nvbench.ps1 new file mode 100644 index 00000000..a39b0b34 --- /dev/null +++ b/ci/windows/build_nvbench.ps1 @@ -0,0 +1,43 @@ +Param( + [Parameter(Mandatory = $false)] + [Alias("std")] + [ValidateNotNullOrEmpty()] + [ValidateSet(17, 20)] + [int]$CXX_STANDARD = 17, + + [Parameter(Mandatory = $false)] + [Alias("arch")] + [string]$CUDA_ARCH = "", + + [Parameter(Mandatory = $false)] + [Alias("cmake-options")] + [string]$CMAKE_OPTIONS = "" +) + +$ErrorActionPreference = "Stop" + +$initialPath = Get-Location +$pushed = $false + +if ((Split-Path $pwd -Leaf) -ne "ci") { + Push-Location "$PSScriptRoot/.." + $pushed = $true +} + +try { + Import-Module "$PSScriptRoot/build_common.psm1" -ArgumentList @($CXX_STANDARD, $CUDA_ARCH, $CMAKE_OPTIONS) -Force + + Print-EnvironmentDetails + + $preset = "nvbench-ci" + $localOptions = @( + "-DCMAKE_CXX_STANDARD=$CXX_STANDARD", + "-DCMAKE_CUDA_STANDARD=$CXX_STANDARD" + ) + + Configure-And-Build-Preset "NVBench" $preset $localOptions +} finally { + if ($pushed) { + Set-Location $initialPath + } +}