From d999f40a497a125f076905e5cfc236c3d515b673 Mon Sep 17 00:00:00 2001 From: Andy Jost Date: Thu, 18 Dec 2025 11:05:39 -0800 Subject: [PATCH 1/4] Add CUDA major version compatibility check Add warn_if_cuda_major_version_mismatch() to cuda-bindings that warns when cuda-bindings was compiled for a newer CUDA major version than the installed driver supports. Called by cuda.core on first Device access. --- .github/workflows/backport.yml | 4 +- .github/workflows/bandit.yml | 6 +- .github/workflows/build-docs.yml | 14 +-- .github/workflows/build-wheel.yml | 18 ++-- .github/workflows/ci.yml | 4 +- .github/workflows/cleanup-pr-previews.yml | 2 +- .github/workflows/codeql.yml | 6 +- .github/workflows/coverage.yml | 8 +- .github/workflows/release-upload.yml | 2 +- .github/workflows/release.yml | 6 +- .github/workflows/test-wheel-linux.yml | 18 ++-- .github/workflows/test-wheel-windows.yml | 18 ++-- cuda_bindings/cuda/bindings/utils/__init__.py | 1 + .../cuda/bindings/utils/_version_check.py | 56 +++++++++++ .../docs/source/environment_variables.rst | 2 + cuda_bindings/tests/test_version_check.py | 98 +++++++++++++++++++ cuda_core/cuda/core/_device.pyx | 6 ++ cuda_core/pixi.lock | 12 +-- pixi.lock | 21 ++++ pixi.toml | 50 ++++++++++ 20 files changed, 293 insertions(+), 59 deletions(-) create mode 100644 cuda_bindings/cuda/bindings/utils/_version_check.py create mode 100644 cuda_bindings/tests/test_version_check.py create mode 100644 pixi.lock create mode 100644 pixi.toml diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml index 83413bf762..c06ac0d120 100644 --- a/.github/workflows/backport.yml +++ b/.github/workflows/backport.yml @@ -23,7 +23,7 @@ jobs: }} runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - name: Load branch name id: get-branch @@ -32,7 +32,7 @@ jobs: echo "OLD_BRANCH=${OLD_BRANCH}" >> $GITHUB_ENV - name: Create backport pull requests - uses: korthout/backport-action@d07416681cab29bf2661702f925f020aaa962997 # v3.4.1 + uses: korthout/backport-action@c656f5d5851037b2b38fb5db2691a03fa229e3b2 # v4.0.1 with: copy_assignees: true copy_labels_pattern: true diff --git a/.github/workflows/bandit.yml b/.github/workflows/bandit.yml index 93cb8c7514..c9fee3938a 100644 --- a/.github/workflows/bandit.yml +++ b/.github/workflows/bandit.yml @@ -20,10 +20,10 @@ jobs: security-events: write steps: - name: Checkout - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - name: Install uv - uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0 + uses: astral-sh/setup-uv@681c641aba71e4a1c380be3ab5e12ad51f415867 # v7.1.6 with: enable-cache: false @@ -42,6 +42,6 @@ jobs: with: args: "check --select S --ignore ${{ steps.ignore-codes.outputs.codes }} --output-format sarif --output-file results.sarif" - name: Upload SARIF file - uses: github/codeql-action/upload-sarif@v3 + uses: github/codeql-action/upload-sarif@v4 with: sarif_file: results.sarif diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index 06e28fd1bf..f2d8d4135e 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -48,7 +48,7 @@ jobs: shell: bash -el {0} steps: - name: Checkout ${{ github.event.repository.name }} - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: fetch-depth: 0 ref: ${{ inputs.git-tag }} @@ -103,7 +103,7 @@ jobs: echo "CUDA_BINDINGS_ARTIFACTS_DIR=$(realpath "$REPO_DIR/cuda_bindings/dist")" >> $GITHUB_ENV - name: Download cuda-python build artifacts - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 with: name: cuda-python-wheel path: . @@ -116,7 +116,7 @@ jobs: ls -lahR . - name: Download cuda-pathfinder build artifacts - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 with: name: cuda-pathfinder-wheel path: ./cuda_pathfinder @@ -130,14 +130,14 @@ jobs: - name: Download cuda.bindings build artifacts if: ${{ !inputs.is-release }} - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 with: name: ${{ env.CUDA_BINDINGS_ARTIFACT_NAME }} path: ${{ env.CUDA_BINDINGS_ARTIFACTS_DIR }} - name: Download cuda.bindings build artifacts if: ${{ inputs.is-release }} - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 with: pattern: ${{ env.CUDA_BINDINGS_ARTIFACT_NAME }} merge-multiple: true @@ -152,14 +152,14 @@ jobs: - name: Download cuda.core build artifacts if: ${{ !inputs.is-release }} - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 with: name: ${{ env.CUDA_CORE_ARTIFACT_NAME }} path: ${{ env.CUDA_CORE_ARTIFACTS_DIR }} - name: Download cuda.core build artifacts if: ${{ inputs.is-release }} - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 with: pattern: ${{ env.CUDA_CORE_ARTIFACT_NAME }} merge-multiple: true diff --git a/.github/workflows/build-wheel.yml b/.github/workflows/build-wheel.yml index 49f999b2fb..823849be02 100644 --- a/.github/workflows/build-wheel.yml +++ b/.github/workflows/build-wheel.yml @@ -40,7 +40,7 @@ jobs: (inputs.host-platform == 'win-64' && 'windows-2022') }} steps: - name: Checkout ${{ github.event.repository.name }} - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: fetch-depth: 0 @@ -65,7 +65,7 @@ jobs: - name: Set up Python id: setup-python1 - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 with: # WAR: setup-python is not relocatable, and cibuildwheel hard-wires to 3.12... # see https://github.com/actions/setup-python/issues/871 @@ -134,7 +134,7 @@ jobs: - name: Upload cuda.pathfinder build artifacts if: ${{ strategy.job-index == 0 && inputs.host-platform == 'linux-64' }} - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 with: name: cuda-pathfinder-wheel path: cuda_pathfinder/*.whl @@ -195,7 +195,7 @@ jobs: twine check --strict ${{ env.CUDA_BINDINGS_ARTIFACTS_DIR }}/*.whl - name: Upload cuda.bindings build artifacts - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 with: name: ${{ env.CUDA_BINDINGS_ARTIFACT_NAME }} path: ${{ env.CUDA_BINDINGS_ARTIFACTS_DIR }}/*.whl @@ -282,7 +282,7 @@ jobs: - name: Upload cuda-python build artifacts if: ${{ strategy.job-index == 0 && inputs.host-platform == 'linux-64' }} - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 with: name: cuda-python-wheel path: cuda_python/*.whl @@ -290,7 +290,7 @@ jobs: - name: Set up Python id: setup-python2 - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 with: python-version: ${{ matrix.python-version }} @@ -320,7 +320,7 @@ jobs: popd - name: Upload cuda.bindings Cython tests - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 with: name: ${{ env.CUDA_BINDINGS_ARTIFACT_NAME }}-tests path: ${{ env.CUDA_BINDINGS_CYTHON_TESTS_DIR }}/test_*${{ env.PY_EXT_SUFFIX }} @@ -334,7 +334,7 @@ jobs: popd - name: Upload cuda.core Cython tests - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 with: name: ${{ env.CUDA_CORE_ARTIFACT_NAME }}-tests path: ${{ env.CUDA_CORE_CYTHON_TESTS_DIR }}/test_*${{ env.PY_EXT_SUFFIX }} @@ -453,7 +453,7 @@ jobs: twine check --strict ${{ env.CUDA_CORE_ARTIFACTS_DIR }}/*.whl - name: Upload cuda.core build artifacts - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 with: name: ${{ env.CUDA_CORE_ARTIFACT_NAME }} path: ${{ env.CUDA_CORE_ARTIFACTS_DIR }}/*.whl diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8733498d91..96d78b945f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,7 +24,7 @@ jobs: CUDA_PREV_BUILD_VER: ${{ steps.get-vars.outputs.cuda_prev_build_ver }} steps: - name: Checkout repository - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: fetch-depth: 0 - name: Get CUDA build versions @@ -42,7 +42,7 @@ jobs: skip: ${{ steps.get-should-skip.outputs.skip }} steps: - name: Checkout repository - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - name: Compute whether to skip builds and tests id: get-should-skip env: diff --git a/.github/workflows/cleanup-pr-previews.yml b/.github/workflows/cleanup-pr-previews.yml index 2207b87490..872b2fe37d 100644 --- a/.github/workflows/cleanup-pr-previews.yml +++ b/.github/workflows/cleanup-pr-previews.yml @@ -28,7 +28,7 @@ jobs: if: github.repository_owner == 'NVIDIA' steps: - name: Checkout repository - uses: actions/checkout@v6 + uses: actions/checkout@v6.0.1 with: # Fetch all history and branches for worktree operations fetch-depth: 0 diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 3926e26887..a79182b5ef 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -28,16 +28,16 @@ jobs: build-mode: none steps: - name: Checkout repository - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - name: Initialize CodeQL - uses: github/codeql-action/init@2d92b76c45b91eb80fc44c74ce3fce0ee94e8f9d # v3.30.0 + uses: github/codeql-action/init@f47c8e6a9bd05ef3ee422fc8d8663be7fe4bdc61 # v3.31.8 with: languages: ${{ matrix.language }} build-mode: ${{ matrix.build-mode }} queries: security-extended - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@2d92b76c45b91eb80fc44c74ce3fce0ee94e8f9d # v3.30.0 + uses: github/codeql-action/analyze@f47c8e6a9bd05ef3ee422fc8d8663be7fe4bdc61 # v3.31.8 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 5aad59a538..c7f3162ecd 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -49,7 +49,7 @@ jobs: apt-get install -y git - name: Checkout ${{ github.event.repository.name }} - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - name: Install dependencies uses: ./.github/actions/install_unix_deps @@ -75,7 +75,7 @@ jobs: echo "CUDA_PYTHON_COVERAGE=1" >> $GITHUB_ENV - name: Set up Python - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 with: python-version: ${{ env.PY_VER }} env: @@ -145,13 +145,13 @@ jobs: mv htmlcov $REPO_ROOT/docs/coverage - name: Archive code coverage results - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 with: name: coverage path: docs/coverage/ - name: Deploy to gh-pages - uses: JamesIves/github-pages-deploy-action@4a3abc783e1a24aeb44c16e869ad83caf6b4cc23 # v4.7.4 + uses: JamesIves/github-pages-deploy-action@9d877eea73427180ae43cf98e8914934fe157a1a # v4.7.6 with: git-config-name: cuda-python-bot git-config-email: cuda-python-bot@users.noreply.github.com diff --git a/.github/workflows/release-upload.yml b/.github/workflows/release-upload.yml index 8ae08c5026..ab69a82e7f 100644 --- a/.github/workflows/release-upload.yml +++ b/.github/workflows/release-upload.yml @@ -41,7 +41,7 @@ jobs: ARCHIVE_NAME: ${{ github.event.repository.name }}-${{ inputs.git-tag }} steps: - name: Checkout Source - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: fetch-depth: 0 ref: ${{ inputs.git-tag }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7d8201810c..530372240a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -50,7 +50,7 @@ jobs: run-id: ${{ steps.lookup-run-id.outputs.run-id }} steps: - name: Checkout Source - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: # fetch-depth: 0 is required so the lookup-run-id script can access all git tags fetch-depth: 0 @@ -74,7 +74,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Source - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: fetch-depth: 0 @@ -155,7 +155,7 @@ jobs: id-token: write steps: - name: Checkout Source - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - name: Download component wheels env: diff --git a/.github/workflows/test-wheel-linux.yml b/.github/workflows/test-wheel-linux.yml index 75a0c4193b..66e5a73508 100644 --- a/.github/workflows/test-wheel-linux.yml +++ b/.github/workflows/test-wheel-linux.yml @@ -36,7 +36,7 @@ jobs: OLD_BRANCH: ${{ steps.compute-matrix.outputs.OLD_BRANCH }} steps: - name: Checkout ${{ github.event.repository.name }} - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - name: Validate Test Type run: | @@ -93,7 +93,7 @@ jobs: run: nvidia-smi - name: Checkout ${{ github.event.repository.name }} - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - name: Setup proxy cache uses: nv-gha-runners/setup-proxy-cache@main @@ -118,21 +118,21 @@ jobs: run: ./ci/tools/env-vars test - name: Download cuda-pathfinder build artifacts - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 with: name: cuda-pathfinder-wheel path: ./cuda_pathfinder - name: Download cuda-python build artifacts if: ${{ env.SKIP_CUDA_BINDINGS_TEST == '0'}} - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 with: name: cuda-python-wheel path: . - name: Download cuda.bindings build artifacts if: ${{ env.SKIP_CUDA_BINDINGS_TEST == '0'}} - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 with: name: ${{ env.CUDA_BINDINGS_ARTIFACT_NAME }} path: ${{ env.CUDA_BINDINGS_ARTIFACTS_DIR }} @@ -184,7 +184,7 @@ jobs: - name: Download cuda.bindings Cython tests if: ${{ env.SKIP_CYTHON_TEST == '0' }} - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 with: name: ${{ env.CUDA_BINDINGS_ARTIFACT_NAME }}-tests path: ${{ env.CUDA_BINDINGS_CYTHON_TESTS_DIR }} @@ -196,7 +196,7 @@ jobs: ls -lahR $CUDA_BINDINGS_CYTHON_TESTS_DIR - name: Download cuda.core build artifacts - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 with: name: ${{ env.CUDA_CORE_ARTIFACT_NAME }} path: ${{ env.CUDA_CORE_ARTIFACTS_DIR }} @@ -208,7 +208,7 @@ jobs: - name: Download cuda.core Cython tests if: ${{ env.SKIP_CYTHON_TEST == '0' }} - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 with: name: ${{ env.CUDA_CORE_ARTIFACT_NAME }}-tests path: ${{ env.CUDA_CORE_CYTHON_TESTS_DIR }} @@ -220,7 +220,7 @@ jobs: ls -lahR $CUDA_CORE_CYTHON_TESTS_DIR - name: Set up Python ${{ matrix.PY_VER }} - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 with: python-version: ${{ matrix.PY_VER }} env: diff --git a/.github/workflows/test-wheel-windows.yml b/.github/workflows/test-wheel-windows.yml index b98e9ba2d7..e9c20a625c 100644 --- a/.github/workflows/test-wheel-windows.yml +++ b/.github/workflows/test-wheel-windows.yml @@ -33,7 +33,7 @@ jobs: MATRIX: ${{ steps.compute-matrix.outputs.MATRIX }} steps: - name: Checkout ${{ github.event.repository.name }} - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - name: Validate Test Type run: | @@ -69,7 +69,7 @@ jobs: runs-on: "windows-${{ matrix.ARCH }}-gpu-${{ matrix.GPU }}-${{ matrix.DRIVER }}-1" steps: - name: Checkout ${{ github.event.repository.name }} - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - name: Setup proxy cache uses: nv-gha-runners/setup-proxy-cache@main @@ -106,21 +106,21 @@ jobs: run: ./ci/tools/env-vars test - name: Download cuda-pathfinder build artifacts - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 with: name: cuda-pathfinder-wheel path: ./cuda_pathfinder - name: Download cuda-python build artifacts if: ${{ env.SKIP_CUDA_BINDINGS_TEST == '0'}} - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 with: name: cuda-python-wheel path: . - name: Download cuda.bindings build artifacts if: ${{ env.SKIP_CUDA_BINDINGS_TEST == '0'}} - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 with: name: ${{ env.CUDA_BINDINGS_ARTIFACT_NAME }} path: ${{ env.CUDA_BINDINGS_ARTIFACTS_DIR }} @@ -163,7 +163,7 @@ jobs: - name: Download cuda.bindings Cython tests if: ${{ env.SKIP_CYTHON_TEST == '0' }} - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 with: name: ${{ env.CUDA_BINDINGS_ARTIFACT_NAME }}-tests path: ${{ env.CUDA_BINDINGS_CYTHON_TESTS_DIR }} @@ -175,7 +175,7 @@ jobs: Get-ChildItem -Recurse -Force $env:CUDA_BINDINGS_CYTHON_TESTS_DIR | Select-Object Mode, LastWriteTime, Length, FullName - name: Download cuda.core build artifacts - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 with: name: ${{ env.CUDA_CORE_ARTIFACT_NAME }} path: ${{ env.CUDA_CORE_ARTIFACTS_DIR }} @@ -187,7 +187,7 @@ jobs: - name: Download cuda.core Cython tests if: ${{ env.SKIP_CYTHON_TEST == '0' }} - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 with: name: ${{ env.CUDA_CORE_ARTIFACT_NAME }}-tests path: ${{ env.CUDA_CORE_CYTHON_TESTS_DIR }} @@ -199,7 +199,7 @@ jobs: Get-ChildItem -Recurse -Force $env:CUDA_CORE_CYTHON_TESTS_DIR | Select-Object Mode, LastWriteTime, Length, FullName - name: Set up Python ${{ matrix.PY_VER }} - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 with: python-version: ${{ matrix.PY_VER }} diff --git a/cuda_bindings/cuda/bindings/utils/__init__.py b/cuda_bindings/cuda/bindings/utils/__init__.py index a2dfe7ce8b..e4fcb15e8f 100644 --- a/cuda_bindings/cuda/bindings/utils/__init__.py +++ b/cuda_bindings/cuda/bindings/utils/__init__.py @@ -3,6 +3,7 @@ from typing import Any, Callable from ._ptx_utils import get_minimal_required_cuda_ver_from_ptx_ver, get_ptx_ver +from ._version_check import warn_if_cuda_major_version_mismatch _handle_getters: dict[type, Callable[[Any], int]] = {} diff --git a/cuda_bindings/cuda/bindings/utils/_version_check.py b/cuda_bindings/cuda/bindings/utils/_version_check.py new file mode 100644 index 0000000000..6e25d0cec2 --- /dev/null +++ b/cuda_bindings/cuda/bindings/utils/_version_check.py @@ -0,0 +1,56 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE + +import os +import warnings + +# Track whether we've already checked major version compatibility +_major_version_compatibility_checked = False + + +def warn_if_cuda_major_version_mismatch(): + """Warn if the CUDA driver major version is older than cuda-bindings compile-time version. + + This function compares the CUDA major version that cuda-bindings was compiled + against with the CUDA major version supported by the installed driver. If the + compile-time major version is greater than the driver's major version, a warning + is issued. + + The check runs only once per process. Subsequent calls are no-ops. + + The warning can be suppressed by setting the environment variable + ``CUDA_PYTHON_DISABLE_MAJOR_VERSION_WARNING=1``. + """ + global _major_version_compatibility_checked + if _major_version_compatibility_checked: + return + _major_version_compatibility_checked = True + + # Allow users to suppress the warning + if os.environ.get("CUDA_PYTHON_DISABLE_MAJOR_VERSION_WARNING"): + return + + # Import here to avoid circular imports and allow lazy loading + from cuda.bindings import driver + + # Get compile-time CUDA version from cuda-bindings + compile_version = driver.CUDA_VERSION # e.g., 13010 + compile_major = compile_version // 1000 + + # Get runtime driver version + err, runtime_version = driver.cuDriverGetVersion() + if err != driver.CUresult.CUDA_SUCCESS: + raise RuntimeError(f"Failed to query CUDA driver version: {err}") + + runtime_major = runtime_version // 1000 + + if compile_major > runtime_major: + warnings.warn( + f"cuda-bindings was built for CUDA major version {compile_major}, but the " + f"NVIDIA driver only supports up to CUDA {runtime_major}. Some cuda-bindings " + f"features may not work correctly. Consider updating your NVIDIA driver, " + f"or using a cuda-bindings version built for CUDA {runtime_major}. " + f"(Set CUDA_PYTHON_DISABLE_MAJOR_VERSION_WARNING=1 to suppress this warning.)", + UserWarning, + stacklevel=3, + ) diff --git a/cuda_bindings/docs/source/environment_variables.rst b/cuda_bindings/docs/source/environment_variables.rst index a212bfe764..7a49fb66a3 100644 --- a/cuda_bindings/docs/source/environment_variables.rst +++ b/cuda_bindings/docs/source/environment_variables.rst @@ -9,6 +9,8 @@ Runtime Environment Variables - ``CUDA_PYTHON_CUDA_PER_THREAD_DEFAULT_STREAM`` : When set to 1, the default stream is the per-thread default stream. When set to 0, the default stream is the legacy default stream. This defaults to 0, for the legacy default stream. See `Stream Synchronization Behavior `_ for an explanation of the legacy and per-thread default streams. +- ``CUDA_PYTHON_DISABLE_MAJOR_VERSION_WARNING`` : When set to 1, suppresses warnings about CUDA major version mismatches between ``cuda-bindings`` and the installed driver. + Build-Time Environment Variables -------------------------------- diff --git a/cuda_bindings/tests/test_version_check.py b/cuda_bindings/tests/test_version_check.py new file mode 100644 index 0000000000..42643dd6e7 --- /dev/null +++ b/cuda_bindings/tests/test_version_check.py @@ -0,0 +1,98 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE + +import os +import warnings +from unittest import mock + +import pytest +from cuda.bindings import driver +from cuda.bindings.utils import _version_check, warn_if_cuda_major_version_mismatch + + +class TestVersionCompatibilityCheck: + """Tests for CUDA major version mismatch warning function.""" + + def setup_method(self): + """Reset the version compatibility check flag before each test.""" + _version_check._major_version_compatibility_checked = False + + def teardown_method(self): + """Reset the version compatibility check flag after each test.""" + _version_check._major_version_compatibility_checked = False + + def test_no_warning_when_driver_newer(self): + """No warning should be issued when driver version >= compile version.""" + # Mock compile version 12.9 and driver version 13.0 + with ( + mock.patch.object(driver, "CUDA_VERSION", 12090), + mock.patch.object(driver, "cuDriverGetVersion", return_value=(driver.CUresult.CUDA_SUCCESS, 13000)), + warnings.catch_warnings(record=True) as w, + ): + warnings.simplefilter("always") + warn_if_cuda_major_version_mismatch() + assert len(w) == 0 + + def test_no_warning_when_same_major_version(self): + """No warning should be issued when major versions match.""" + # Mock compile version 12.9 and driver version 12.8 + with ( + mock.patch.object(driver, "CUDA_VERSION", 12090), + mock.patch.object(driver, "cuDriverGetVersion", return_value=(driver.CUresult.CUDA_SUCCESS, 12080)), + warnings.catch_warnings(record=True) as w, + ): + warnings.simplefilter("always") + warn_if_cuda_major_version_mismatch() + assert len(w) == 0 + + def test_warning_when_compile_major_newer(self): + """Warning should be issued when compile major version > driver major version.""" + # Mock compile version 13.0 and driver version 12.8 + with ( + mock.patch.object(driver, "CUDA_VERSION", 13000), + mock.patch.object(driver, "cuDriverGetVersion", return_value=(driver.CUresult.CUDA_SUCCESS, 12080)), + warnings.catch_warnings(record=True) as w, + ): + warnings.simplefilter("always") + warn_if_cuda_major_version_mismatch() + assert len(w) == 1 + assert issubclass(w[0].category, UserWarning) + assert "cuda-bindings was built for CUDA major version 13" in str(w[0].message) + assert "only supports up to CUDA 12" in str(w[0].message) + + def test_warning_only_issued_once(self): + """Warning should only be issued once per process.""" + with ( + mock.patch.object(driver, "CUDA_VERSION", 13000), + mock.patch.object(driver, "cuDriverGetVersion", return_value=(driver.CUresult.CUDA_SUCCESS, 12080)), + warnings.catch_warnings(record=True) as w, + ): + warnings.simplefilter("always") + warn_if_cuda_major_version_mismatch() + warn_if_cuda_major_version_mismatch() + warn_if_cuda_major_version_mismatch() + # Only one warning despite multiple calls + assert len(w) == 1 + + def test_warning_suppressed_by_env_var(self): + """Warning should be suppressed when CUDA_PYTHON_DISABLE_MAJOR_VERSION_WARNING is set.""" + with ( + mock.patch.object(driver, "CUDA_VERSION", 13000), + mock.patch.object(driver, "cuDriverGetVersion", return_value=(driver.CUresult.CUDA_SUCCESS, 12080)), + mock.patch.dict(os.environ, {"CUDA_PYTHON_DISABLE_MAJOR_VERSION_WARNING": "1"}), + warnings.catch_warnings(record=True) as w, + ): + warnings.simplefilter("always") + warn_if_cuda_major_version_mismatch() + assert len(w) == 0 + + def test_error_when_driver_version_fails(self): + """Should raise RuntimeError if cuDriverGetVersion fails.""" + with ( + mock.patch.object(driver, "CUDA_VERSION", 13000), + mock.patch.object( + driver, "cuDriverGetVersion", return_value=(driver.CUresult.CUDA_ERROR_NOT_INITIALIZED, 0) + ), + pytest.raises(RuntimeError, match="Failed to query CUDA driver version"), + ): + warn_if_cuda_major_version_mismatch() diff --git a/cuda_core/cuda/core/_device.pyx b/cuda_core/cuda/core/_device.pyx index 2d775b6580..2c7b25e23e 100644 --- a/cuda_core/cuda/core/_device.pyx +++ b/cuda_core/cuda/core/_device.pyx @@ -16,6 +16,10 @@ from cuda.core._event import Event, EventOptions from cuda.core._graph import GraphBuilder from cuda.core._stream import IsStreamT, Stream, StreamOptions from cuda.core._utils.clear_error_support import assert_type +try: + from cuda.bindings.utils import warn_if_cuda_major_version_mismatch +except ImportError: + warn_if_cuda_major_version_mismatch = lambda: None from cuda.core._utils.cuda_utils import ( ComputeCapability, CUDAError, @@ -963,6 +967,8 @@ class Device: with _lock, nogil: HANDLE_RETURN(cydriver.cuInit(0)) _is_cuInit = True + # Check version compatibility after CUDA is initialized + warn_if_cuda_major_version_mismatch() # important: creating a Device instance does not initialize the GPU! cdef cydriver.CUdevice dev diff --git a/cuda_core/pixi.lock b/cuda_core/pixi.lock index 16a0d2460f..f818f586da 100644 --- a/cuda_core/pixi.lock +++ b/cuda_core/pixi.lock @@ -1051,7 +1051,7 @@ packages: timestamp: 1764878612030 - conda: . name: cuda-core - version: 0.4.2 + version: 0.5.0 build: py314h59f3c06_0 subdir: linux-64 variants: @@ -1068,12 +1068,12 @@ packages: - cuda-cudart >=13.1.80,<14.0a0 license: Apache-2.0 input: - hash: cccb645b22f775570680f1a9a62e415a09774e46645523bbd147226681155628 + hash: 1ca5e93f36385c628c555ad7ff2bbacd659238db16f10d477ece67c394b562f5 globs: - pyproject.toml - conda: . name: cuda-core - version: 0.4.2 + version: 0.5.0 build: py314h625260f_0 subdir: win-64 variants: @@ -1088,12 +1088,12 @@ packages: - python_abi 3.14.* *_cp314 license: Apache-2.0 input: - hash: cccb645b22f775570680f1a9a62e415a09774e46645523bbd147226681155628 + hash: 1ca5e93f36385c628c555ad7ff2bbacd659238db16f10d477ece67c394b562f5 globs: - pyproject.toml - conda: . name: cuda-core - version: 0.4.2 + version: 0.5.0 build: py314ha479ada_0 subdir: linux-aarch64 variants: @@ -1110,7 +1110,7 @@ packages: - cuda-cudart >=13.1.80,<14.0a0 license: Apache-2.0 input: - hash: cccb645b22f775570680f1a9a62e415a09774e46645523bbd147226681155628 + hash: 1ca5e93f36385c628c555ad7ff2bbacd659238db16f10d477ece67c394b562f5 globs: - pyproject.toml - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-crt-dev_linux-64-12.9.86-ha770c72_2.conda diff --git a/pixi.lock b/pixi.lock new file mode 100644 index 0000000000..fa9b0c1c11 --- /dev/null +++ b/pixi.lock @@ -0,0 +1,21 @@ +version: 6 +environments: + cu12: + channels: + - url: https://conda.anaconda.org/conda-forge/ + options: + pypi-prerelease-mode: if-necessary-or-explicit + packages: {} + cu13: + channels: + - url: https://conda.anaconda.org/conda-forge/ + options: + pypi-prerelease-mode: if-necessary-or-explicit + packages: {} + default: + channels: + - url: https://conda.anaconda.org/conda-forge/ + options: + pypi-prerelease-mode: if-necessary-or-explicit + packages: {} +packages: [] diff --git a/pixi.toml b/pixi.toml new file mode 100644 index 0000000000..c85559e8a7 --- /dev/null +++ b/pixi.toml @@ -0,0 +1,50 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# +# SPDX-License-Identifier: Apache-2.0 + +[workspace] +channels = ["conda-forge"] +platforms = ["linux-64", "linux-aarch64", "win-64"] + +[feature.cu12.dependencies] +[feature.cu13.dependencies] + +[environments] +cu12 = { features = ["cu12"] } +cu13 = { features = ["cu13"] } + +[activation.env] +PIXI_ENVIRONMENT_NAME = "${PIXI_ENVIRONMENT_NAME/default/cu13}" + +# Test Tasks +# Runs tests across all sub-packages: pathfinder → bindings → core (dependency order) +# Each sub-package has its own pixi.toml; the -e environment propagates via PIXI_ENVIRONMENT_NAME +# +# Usage: pixi run test | pixi run -e cu12 test | pixi run -e cu13 test +[target.linux.tasks.test-pathfinder] +cmd = [ + "pixi", + "run", + "--manifest-path", + "$PIXI_PROJECT_ROOT/cuda_pathfinder", + "test", +] + +[target.linux.tasks.test-bindings] +cmd = [ + "pixi", + "run", + "--manifest-path", + "$PIXI_PROJECT_ROOT/cuda_bindings", + "test", +] + +[target.linux.tasks.test-core] +cmd = ["pixi", "run", "--manifest-path", "$PIXI_PROJECT_ROOT/cuda_core", "test"] + +[target.linux.tasks.test] +depends-on = [ + { task = "test-pathfinder" }, + { task = "test-bindings" }, + { task = "test-core" }, +] From 73611ed4f2abb8f592cae0012bdff845ceb2bcf2 Mon Sep 17 00:00:00 2001 From: Andy Jost Date: Thu, 8 Jan 2026 09:59:15 -0800 Subject: [PATCH 2/4] Move version check import to local scope Import warn_if_cuda_major_version_mismatch locally in Device.__new__ after cuInit, using try/except/else pattern instead of module-level import with lambda fallback. --- cuda_core/cuda/core/_device.pyx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/cuda_core/cuda/core/_device.pyx b/cuda_core/cuda/core/_device.pyx index 085a49d193..0dff37d861 100644 --- a/cuda_core/cuda/core/_device.pyx +++ b/cuda_core/cuda/core/_device.pyx @@ -16,10 +16,6 @@ from cuda.core._event import Event, EventOptions from cuda.core._graph import GraphBuilder from cuda.core._stream import IsStreamT, Stream, StreamOptions from cuda.core._utils.clear_error_support import assert_type -try: - from cuda.bindings.utils import warn_if_cuda_major_version_mismatch -except ImportError: - warn_if_cuda_major_version_mismatch = lambda: None from cuda.core._utils.cuda_utils import ( ComputeCapability, CUDAError, @@ -972,7 +968,12 @@ class Device: HANDLE_RETURN(cydriver.cuInit(0)) _is_cuInit = True # Check version compatibility after CUDA is initialized - warn_if_cuda_major_version_mismatch() + try: + from cuda.bindings.utils import warn_if_cuda_major_version_mismatch + except ImportError: + pass + else: + warn_if_cuda_major_version_mismatch() # important: creating a Device instance does not initialize the GPU! cdef cydriver.CUdevice dev From fdb3a7e896bfaa1e5a79823f0a5b1563aa2d2043 Mon Sep 17 00:00:00 2001 From: Andy Jost Date: Thu, 8 Jan 2026 10:16:50 -0800 Subject: [PATCH 3/4] Refactor Device.__new__ into helper functions Extract Device.__new__ logic into cdef helper functions: - Device_ensure_cuda_initialized(): cuInit + version check - Device_resolve_device_id(): resolve None to current device or 0 - Device_ensure_tls_devices(): create thread-local singletons Reduces Device.__new__ from ~60 lines to ~12 lines. Helpers placed after Device class following memory module pattern. --- cuda_core/cuda/core/_device.pyx | 111 +++++++++++++++++--------------- 1 file changed, 60 insertions(+), 51 deletions(-) diff --git a/cuda_core/cuda/core/_device.pyx b/cuda_core/cuda/core/_device.pyx index cef371b5e6..1ec6989473 100644 --- a/cuda_core/cuda/core/_device.pyx +++ b/cuda_core/cuda/core/_device.pyx @@ -965,60 +965,12 @@ class Device: __slots__ = ("_id", "_memory_resource", "_has_inited", "_properties", "_uuid") def __new__(cls, device_id: Device | int | None = None): - # Handle device_id argument. if isinstance(device_id, Device): return device_id - else: - device_id = getattr(device_id, 'device_id', device_id) - - # Initialize CUDA. - global _is_cuInit - if _is_cuInit is False: - with _lock, nogil: - HANDLE_RETURN(cydriver.cuInit(0)) - _is_cuInit = True - # Check version compatibility after CUDA is initialized - try: - from cuda.bindings.utils import warn_if_cuda_major_version_mismatch - except ImportError: - pass - else: - warn_if_cuda_major_version_mismatch() - - # important: creating a Device instance does not initialize the GPU! - cdef cydriver.CUdevice dev - cdef cydriver.CUcontext ctx - if device_id is None: - with nogil: - err = cydriver.cuCtxGetDevice(&dev) - if err == cydriver.CUresult.CUDA_SUCCESS: - device_id = int(dev) - elif err == cydriver.CUresult.CUDA_ERROR_INVALID_CONTEXT: - with nogil: - HANDLE_RETURN(cydriver.cuCtxGetCurrent(&ctx)) - assert (ctx) == NULL - device_id = 0 # cudart behavior - else: - HANDLE_RETURN(err) - elif device_id < 0: - raise ValueError(f"device_id must be >= 0, got {device_id}") - # ensure Device is singleton - cdef int total - try: - devices = _tls.devices - except AttributeError: - with nogil: - HANDLE_RETURN(cydriver.cuDeviceGetCount(&total)) - devices = _tls.devices = [] - for dev_id in range(total): - device = super().__new__(cls) - device._id = dev_id - device._memory_resource = None - device._has_inited = False - device._properties = None - device._uuid = None - devices.append(device) + Device_ensure_cuda_initialized() + device_id = Device_resolve_device_id(device_id) + devices = Device_ensure_tls_devices(cls) try: return devices[device_id] @@ -1413,3 +1365,60 @@ class Device: """ self._check_context_initialized() return GraphBuilder._init(stream=self.create_stream(), is_stream_owner=True) + + +cdef inline void Device_ensure_cuda_initialized() except *: + """Initialize CUDA driver and check version compatibility (once per process).""" + global _is_cuInit + if _is_cuInit is False: + with _lock, nogil: + HANDLE_RETURN(cydriver.cuInit(0)) + _is_cuInit = True + try: + from cuda.bindings.utils import warn_if_cuda_major_version_mismatch + except ImportError: + pass + else: + warn_if_cuda_major_version_mismatch() + + +cdef inline int Device_resolve_device_id(device_id) except? -1: + """Resolve device_id, defaulting to current device or 0.""" + cdef cydriver.CUdevice dev + cdef cydriver.CUcontext ctx + cdef cydriver.CUresult err + if device_id is None: + with nogil: + err = cydriver.cuCtxGetDevice(&dev) + if err == cydriver.CUresult.CUDA_SUCCESS: + return int(dev) + elif err == cydriver.CUresult.CUDA_ERROR_INVALID_CONTEXT: + with nogil: + HANDLE_RETURN(cydriver.cuCtxGetCurrent(&ctx)) + assert (ctx) == NULL + return 0 # cudart behavior + else: + HANDLE_RETURN(err) + elif device_id < 0: + raise ValueError(f"device_id must be >= 0, got {device_id}") + return device_id + + +cdef inline list Device_ensure_tls_devices(cls): + """Ensure thread-local Device singletons exist, creating if needed.""" + cdef int total + try: + return _tls.devices + except AttributeError: + with nogil: + HANDLE_RETURN(cydriver.cuDeviceGetCount(&total)) + devices = _tls.devices = [] + for dev_id in range(total): + device = super(Device, cls).__new__(cls) + device._id = dev_id + device._memory_resource = None + device._has_inited = False + device._properties = None + device._uuid = None + devices.append(device) + return devices From 7f23b08bcbd1e9c0e1899963c6402f5ad996fed6 Mon Sep 17 00:00:00 2001 From: Andy Jost Date: Wed, 14 Jan 2026 09:49:19 -0800 Subject: [PATCH 4/4] test: use monkeypatch to properly save/restore version check flag Replace setup_method/teardown_method with a pytest fixture that uses monkeypatch to properly save and restore the original value of _major_version_compatibility_checked after each test. Minor change to Cython cdef inline helper function signature. --- cuda_bindings/cuda/bindings/utils/_version_check.py | 7 ++++++- cuda_bindings/tests/test_version_check.py | 11 ++++------- cuda_core/cuda/core/_device.pyx | 3 ++- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/cuda_bindings/cuda/bindings/utils/_version_check.py b/cuda_bindings/cuda/bindings/utils/_version_check.py index 6e25d0cec2..1ebd7f3d92 100644 --- a/cuda_bindings/cuda/bindings/utils/_version_check.py +++ b/cuda_bindings/cuda/bindings/utils/_version_check.py @@ -2,10 +2,12 @@ # SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE import os +import threading import warnings # Track whether we've already checked major version compatibility _major_version_compatibility_checked = False +_lock = threading.Lock() def warn_if_cuda_major_version_mismatch(): @@ -24,7 +26,10 @@ def warn_if_cuda_major_version_mismatch(): global _major_version_compatibility_checked if _major_version_compatibility_checked: return - _major_version_compatibility_checked = True + with _lock: + if _major_version_compatibility_checked: + return + _major_version_compatibility_checked = True # Allow users to suppress the warning if os.environ.get("CUDA_PYTHON_DISABLE_MAJOR_VERSION_WARNING"): diff --git a/cuda_bindings/tests/test_version_check.py b/cuda_bindings/tests/test_version_check.py index 42643dd6e7..9862d93cc9 100644 --- a/cuda_bindings/tests/test_version_check.py +++ b/cuda_bindings/tests/test_version_check.py @@ -13,13 +13,10 @@ class TestVersionCompatibilityCheck: """Tests for CUDA major version mismatch warning function.""" - def setup_method(self): - """Reset the version compatibility check flag before each test.""" - _version_check._major_version_compatibility_checked = False - - def teardown_method(self): - """Reset the version compatibility check flag after each test.""" - _version_check._major_version_compatibility_checked = False + @pytest.fixture(autouse=True) + def reset_version_check(self, monkeypatch): + """Reset the version compatibility check flag for each test, restoring after.""" + monkeypatch.setattr(_version_check, "_major_version_compatibility_checked", False) def test_no_warning_when_driver_newer(self): """No warning should be issued when driver version >= compile version.""" diff --git a/cuda_core/cuda/core/_device.pyx b/cuda_core/cuda/core/_device.pyx index 7297fd9cb1..9bd7785efb 100644 --- a/cuda_core/cuda/core/_device.pyx +++ b/cuda_core/cuda/core/_device.pyx @@ -1354,7 +1354,7 @@ class Device: return GraphBuilder._init(stream=self.create_stream(), is_stream_owner=True) -cdef inline void Device_ensure_cuda_initialized() except *: +cdef inline int Device_ensure_cuda_initialized() except? -1: """Initialize CUDA driver and check version compatibility (once per process).""" global _is_cuInit if _is_cuInit is False: @@ -1367,6 +1367,7 @@ cdef inline void Device_ensure_cuda_initialized() except *: pass else: warn_if_cuda_major_version_mismatch() + return 0 cdef inline int Device_resolve_device_id(device_id) except? -1: