diff --git a/.github/actions/build/action.yml.j2 b/.github/actions/build/action.yml similarity index 61% rename from .github/actions/build/action.yml.j2 rename to .github/actions/build/action.yml index 59a6ba29..952fb9cd 100644 --- a/.github/actions/build/action.yml.j2 +++ b/.github/actions/build/action.yml @@ -22,33 +22,14 @@ inputs: upload-enabled: required: true type: boolean + python-version: + required: true + type: string runs: using: composite steps: -<% for package_id, package_info in packages.items() %> - - name: Download <> (artifacts) - uses: ./.github/actions/download-artifacts - with: - artifact-repo: "<>" - artifact-name: "<>" - target-device: "${{ inputs.target-device }}" - git_sha: "<>" - host-platform: ${{ inputs.host-platform }} - dest-dir: ${{ env.ARTIFACTS_DIR }} - dependencies-workflow: <> -<% endfor %> - -<% if packages %> - - - name: Display structure of downloaded artifacts - shell: bash --noprofile --norc -xeuo pipefail {0} - run: | - pwd - ls -lahR ${{ env.ARTIFACTS_DIR }} -<% endif %> - - if: ${{ inputs.use-container }} name: Build (in container) shell: bash --noprofile --norc -xeuo pipefail {0} @@ -60,14 +41,16 @@ runs: -e AWS_ACCESS_KEY_ID \ -e AWS_SECRET_ACCESS_KEY \ -e GITHUB_TOKEN \ - -e ARTIFACTS_DIR="$ARTIFACTS_DIR" \ + -e BINDINGS_ARTIFACTS_DIR="$BINDINGS_ARTIFACTS_DIR" \ + -e CORE_ARTIFACTS_DIR="$CORE_ARTIFACTS_DIR" \ -e UPLOAD_ENABLED="$UPLOAD_ENABLED" \ -e USE_CUDA="$USE_CUDA" \ -e REPO_DIR="$REPO_DIR" \ -e LEGATE_CORE_BUILD_MODE="$LEGATE_CORE_BUILD_MODE" \ -e PYTHON_VERSION="$PYTHON_VERSION" \ -v "${{ env.REPO_DIR }}:${{ env.REPO_DIR }}" \ - -v "${{ env.ARTIFACTS_DIR }}:${{ env.ARTIFACTS_DIR }}" \ + -v "${{ env.BINDINGS_ARTIFACTS_DIR }}:${{ env.BINDINGS_ARTIFACTS_DIR }}" \ + -v "${{ env.CORE_ARTIFACTS_DIR }}:${{ env.CORE_ARTIFACTS_DIR }}" \ --rm "${{ inputs.docker-image }}" \ /bin/bash -c "${{ env.REPO_DIR }}/continuous_integration/scripts/entrypoint ${{ env.REPO_DIR }}/continuous_integration/scripts/build ${{ inputs.build-type}} ${{ inputs.target-device }}" @@ -77,14 +60,26 @@ runs: run: | "${{ env.REPO_DIR }}/continuous_integration/scripts/entrypoint" "${{ env.REPO_DIR }}/continuous_integration/scripts/build" "${{ inputs.build-type}}" "${{ inputs.target-device }}" - - name: Display structure of the artifacts folder (post build) + - name: Display structure of the bindings artifacts folder (post build) + shell: bash --noprofile --norc -xeuo pipefail {0} + run: | + sudo chown -R $(whoami) ${{ env.BINDINGS_ARTIFACTS_DIR }} + ls -lahR ${{ env.BINDINGS_ARTIFACTS_DIR }} + + - name: Upload bindings build artifacts + uses: actions/upload-artifact@v4 + with: + name: ${{ env.BINDINGS_ARTIFACT_NAME }} + path: ${{ env.BINDINGS_ARTIFACTS_DIR }} + + - name: Display structure of the core artifacts folder (post build) shell: bash --noprofile --norc -xeuo pipefail {0} run: | - sudo chown -R $(whoami) ${{ env.ARTIFACTS_DIR }} - ls -lahR ${{ env.ARTIFACTS_DIR }} + sudo chown -R $(whoami) ${{ env.CORE_ARTIFACTS_DIR }} + ls -lahR ${{ env.CORE_ARTIFACTS_DIR }} - - name: Upload build artifacts + - name: Upload core build artifacts uses: actions/upload-artifact@v4 with: - name: ${{ env.ARTIFACT_NAME }} - path: ${{ env.ARTIFACTS_DIR }} + name: ${{ env.CORE_ARTIFACT_NAME }} + path: ${{ env.CORE_ARTIFACTS_DIR }} diff --git a/.github/actions/download-artifacts/action.yml b/.github/actions/download-artifacts/action.yml deleted file mode 100644 index c3dffa02..00000000 --- a/.github/actions/download-artifacts/action.yml +++ /dev/null @@ -1,59 +0,0 @@ -name: download-artifacts - -description: Download dependencies (artifacts) - -inputs: - artifact-repo: - type: string - require: true - artifact-name: - type: string - require: true - target-device: - type: string - required: true - git_sha: - type: string - required: true - host-platform: - type: string - required: true - dest-dir: - type: string - required: true - dependencies-workflow: - required: true - type: string - -runs: - using: composite - steps: - - - id: cache - name: Cache conda artifacts - uses: actions/cache@v4 - with: - key: "nvidia/{ inputs.artifact-repo }}@${{ inputs.host-platform }}-${{ inputs.git_sha }}-${{ inputs.target-device }}" - path: ${{ inputs.dest-dir }} - - - if: steps.cache.outputs.cache-hit != 'true' - name: Download ${{ inputs.artifact-repo }} artifacts - uses: dawidd6/action-download-artifact@v3 - with: - path: ${{ inputs.dest-dir }} - repo: nvidia/${{ inputs.artifact-repo }} - check_artifacts: true - commit: ${{ inputs.git_sha }} - workflow_conclusion: "" - workflow: ${{ inputs.dependencies-workflow }} - name: ${{ inputs.artifact-name }} - skip_unpack: true - if_no_artifact_found: fail - allow_forks: false - - - if: steps.cache.outputs.cache-hit != 'true' - name: Unpack artifact - shell: bash --noprofile --norc -xeuo pipefail {0} - run: | - cd ${{ inputs.dest-dir }} - unzip *.zip diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index adeb48df..c2a8407c 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -20,7 +20,7 @@ inputs: required: true type: boolean python-version: - required: false + required: true type: string runs: @@ -57,12 +57,16 @@ runs: PKG_DIR="${BUILD_MODE}/${TARGET_PLATFORM}" fi - echo "ARTIFACT_NAME=${{ inputs.host-platform }}-${{ inputs.build-type }}-${{ inputs.client-repo }}-python${{ inputs.python-version }}-${{ inputs.target-device }}${BUILD_MODE_STR}${WITH_TESTS_STR}-${{ github.sha }}" >> $GITHUB_ENV - echo "ARTIFACTS_DIR=$(realpath "$(pwd)/dist")" >> $GITHUB_ENV + PYTHON_VERSION_FORMATTED=$(echo '${{ inputs.python-version }}' | tr -d '.') + + echo "BINDINGS_ARTIFACT_NAME=${{ inputs.host-platform }}-${{ inputs.build-type }}-cuda_bindings-python${PYTHON_VERSION_FORMATTED}-${{ inputs.target-device }}${BUILD_MODE_STR}${WITH_TESTS_STR}-${{ github.sha }}" >> $GITHUB_ENV + echo "BINDINGS_ARTIFACTS_DIR=$(realpath "$(pwd)/cuda_bindings/dist")" >> $GITHUB_ENV + echo "CORE_ARTIFACT_NAME=${{ inputs.host-platform }}-${{ inputs.build-type }}-cuda_core-python${PYTHON_VERSION_FORMATTED}-${{ inputs.target-device }}${BUILD_MODE_STR}${WITH_TESTS_STR}-${{ github.sha }}" >> $GITHUB_ENV + echo "CORE_ARTIFACTS_DIR=$(realpath "$(pwd)/cuda_core/dist")" >> $GITHUB_ENV echo "USE_CUDA=${{ (inputs.target-device == 'cpu' && 'OFF') || 'ON' }}" >> $GITHUB_ENV echo "UPLOAD_ENABLED=${{ (inputs.upload-enabled == 'true' && 'ON') || 'OFF' }}" >> $GITHUB_ENV echo "LEGATE_CORE_BUILD_MODE=${BUILD_MODE}" >> $GITHUB_ENV echo "BUILD_DATE=$(date +%Y%m%d)" >> $GITHUB_ENV echo "TARGET_PLATFORM=${TARGET_PLATFORM}" >> $GITHUB_ENV echo "PKG_DIR=${PKG_DIR}" >> $GITHUB_ENV - echo "PYTHON_VERSION=${{ inputs.python-version }}" >> $GITHUB_ENV \ No newline at end of file + echo "PYTHON_VERSION=${{ inputs.python-version }}" >> $GITHUB_ENV diff --git a/.github/workflows/ci-gh.yml b/.github/workflows/ci-gh.yml index 2c43d03f..d38cb8e3 100644 --- a/.github/workflows/ci-gh.yml +++ b/.github/workflows/ci-gh.yml @@ -24,6 +24,9 @@ jobs: - release upload-enabled: - false + python-version: + #TODO cover the whole python and cuda matrix + - 3.12 uses: ./.github/workflows/gh-build-and-test.yml with: @@ -32,4 +35,5 @@ jobs: build-mode: ${{ matrix.build-mode }} build-type: ci upload-enabled: ${{ matrix.upload-enabled }} + python-version: ${{ matrix.python-version }} secrets: inherit diff --git a/.github/workflows/gh-build-and-test.yml b/.github/workflows/gh-build-and-test.yml index 4376776d..430fbf5b 100644 --- a/.github/workflows/gh-build-and-test.yml +++ b/.github/workflows/gh-build-and-test.yml @@ -16,6 +16,9 @@ on: upload-enabled: type: boolean required: true + python-version: + type: string + required: true jobs: build: if: ${{ github.repository_owner == 'nvidia' }} @@ -31,4 +34,5 @@ jobs: dependencies-file: "" build-mode: ${{ inputs.build-mode }} upload-enabled: ${{ inputs.upload-enabled }} + python-version: ${{ inputs.python-version }} secrets: inherit diff --git a/.github/workflows/gh-build.yml b/.github/workflows/gh-build.yml index 922e04ec..c60e0c2a 100644 --- a/.github/workflows/gh-build.yml +++ b/.github/workflows/gh-build.yml @@ -33,7 +33,7 @@ on: required: true type: boolean python-version: - required: false + required: true type: string jobs: @@ -63,27 +63,6 @@ jobs: upload-enabled: ${{ inputs.upload-enabled }} python-version: ${{ inputs.python-version }} - - name: Render templates - shell: bash --noprofile --norc -xeuo pipefail {0} - run: | - pip -q install jinja2 - - DEPENDENCIES_FILE="" - - if [ -z "${{ inputs.dependencies-file }}" ]; then - DEPENDENCIES_FILE="${REPO_DIR}/continuous_integration/no_dependencies.json" - else - DEPENDENCIES_FILE="${REPO_DIR}/${{ inputs.dependencies-file }}" - fi - - ${REPO_DIR}/continuous_integration/scripts/render-template.py .github/actions/build/action.yml.j2 "${DEPENDENCIES_FILE}" .github/actions/build/action.yml - - - name: Dump templates - shell: bash --noprofile --norc -xeuo pipefail {0} - run: | - echo ${REPO_DIR}/.github/actions/build/action.yml - cat ${REPO_DIR}/.github/actions/build/action.yml - - name: Call build action uses: ./.github/actions/build with: diff --git a/continuous_integration/no_dependencies.json b/continuous_integration/no_dependencies.json deleted file mode 100644 index e2d7bd79..00000000 --- a/continuous_integration/no_dependencies.json +++ /dev/null @@ -1 +0,0 @@ -{ "packages" : {} } diff --git a/continuous_integration/scripts/build b/continuous_integration/scripts/build index 5db25e67..618edd5f 100755 --- a/continuous_integration/scripts/build +++ b/continuous_integration/scripts/build @@ -3,11 +3,13 @@ build_ci() { set -xeou pipefail - cd "${REPO_DIR}" - export CUDA_HOME="${CONDA_PREFIX}/targets/x86_64-linux" export PARALLEL_LEVEL=$(nproc --ignore 1) + cd "${REPO_DIR}/cuda_bindings" + python setup.py bdist_wheel + + cd "${REPO_DIR}/cuda_core" python setup.py bdist_wheel } diff --git a/continuous_integration/scripts/generate-environment b/continuous_integration/scripts/generate-environment new file mode 100755 index 00000000..8bf2c38d --- /dev/null +++ b/continuous_integration/scripts/generate-environment @@ -0,0 +1,36 @@ +#!/usr/bin/env bash + +# Function to generate environment.yml +generate_environment_yml() { + local python_version=$1 + local cuda_version=$2 + local output_path=$3 + + cat < "${output_path}/environment.yml" +name: cuda_python +channels: + - defaults + - conda-forge +dependencies: + - python=${python_version} + - cython + - pytest + - numpy + - setuptools + - wheel + - pip + - cuda-version=${cuda_version} + - cuda-cudart-static + - cuda-driver-dev + - cuda-cudart-dev + - cuda-profiler-api + - cuda-nvrtc-dev + - cuda-nvcc + - pip: + - pytest-benchmark + - pyclibrary + - versioneer==0.29 + - tomli; python_version < "3.11" + - pywin32; sys_platform == 'win32' +EOF +} \ No newline at end of file diff --git a/continuous_integration/scripts/make-conda-env b/continuous_integration/scripts/make-conda-env index 1294f038..37539b37 100755 --- a/continuous_integration/scripts/make-conda-env +++ b/continuous_integration/scripts/make-conda-env @@ -3,24 +3,16 @@ set -x make_ci_env() { - mamba env create -n "${CONDA_ENV}" -f "${REPO_DIR}/continuous_integration/environment.yml" -} - -make_test_env() { - . conda-utils - - mamba env create -n "${CONDA_ENV}" -f "${REPO_DIR}/continuous_integration/environment.yml" - - activate_conda_env - - pip install "${ARTIFACTS_DIR}"/*.whl - + #TODO wire cuda version as a top level matrix argument + generate_environment_yml "${PYTHON_VERSION}" 12.6 . + mamba env create -n "${CONDA_ENV}" -f ./environment.yml } make_conda_env() { set -xeuo pipefail . setup-utils; + . generate-environment set_base_defs; case "$1" in diff --git a/continuous_integration/scripts/render-template.py b/continuous_integration/scripts/render-template.py deleted file mode 100755 index b887e361..00000000 --- a/continuous_integration/scripts/render-template.py +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/env python3 - -import argparse -import json -from jinja2 import Environment, FileSystemLoader -import os -import re - -# TODO: make this work for arbitrary context. ie. implement replace_using_context() -def replace_placeholder(source_str, variable_name, variable_value): - # Escaping any regex special characters in variable_name - variable_name_escaped = re.escape(variable_name) - - # Using regular expression to replace ${variable_name} with actual variable_value - # \s* means any amount of whitespace (including none) - # pattern = rf'\$\{{\s*\{{\s*{variable_name_escaped}\s*\}}\s*\}}' - pattern = rf'<<\s*{variable_name_escaped}\s*>>' - return re.sub(pattern, variable_value.strip(), source_str) - -# Setup command-line argument parsing -parser = argparse.ArgumentParser(description='Render a Jinja2 template using a JSON context.') -parser.add_argument('template_file', type=str, help='Path to the Jinja2 template file (with .j2 extension).') -parser.add_argument('json_file', type=str, help='Path to the JSON file to use as the rendering context.') -parser.add_argument('output_file', type=str, help='Path to the output file.') - -args = parser.parse_args() - -# Load JSON file as the rendering context -with open(args.json_file, 'r') as file: - context = json.load(file) - -# Setup Jinja2 environment and load the template -env = Environment( - loader=FileSystemLoader(searchpath='./'), - variable_start_string='<<', - variable_end_string='>>', - block_start_string='<%', - block_end_string='%>', - comment_start_string='<#', - comment_end_string='#>') -env.filters['replace_placeholder'] = replace_placeholder - -template = env.get_template(args.template_file) - -# Render the template with the context -rendered_content = template.render(context) -# print(rendered_content) - -with open(args.output_file, 'w') as file: - file.write(rendered_content) - -print(f'Template rendered successfully. Output saved to {args.output_file}') diff --git a/cuda_bindings/docs/build_docs.sh b/cuda_bindings/docs/build_docs.sh index 4c8dd837..9f618c55 100755 --- a/cuda_bindings/docs/build_docs.sh +++ b/cuda_bindings/docs/build_docs.sh @@ -3,9 +3,13 @@ set -ex # SPHINX_CUDA_BINDINGS_VER is used to create a subdir under build/html -# (the Makefile file for sphinx-build also honors it if defined) +# (the Makefile file for sphinx-build also honors it if defined). +# If there's a post release (ex: .post1) we don't want it to show up in the +# version selector or directory structure. if [[ -z "${SPHINX_CUDA_BINDINGS_VER}" ]]; then - export SPHINX_CUDA_BINDINGS_VER=$(python -c "from importlib.metadata import version; print(version('cuda-python'))" \ + export SPHINX_CUDA_BINDINGS_VER=$(python -c "from importlib.metadata import version; \ + ver = '.'.join(str(version('cuda-python')).split('.')[:3]); \ + print(ver)" \ | awk -F'+' '{print $1}') fi diff --git a/cuda_bindings/docs/source/release/11.8.5-notes.md b/cuda_bindings/docs/source/release/11.8.5-notes.md index 44616459..37498b11 100644 --- a/cuda_bindings/docs/source/release/11.8.5-notes.md +++ b/cuda_bindings/docs/source/release/11.8.5-notes.md @@ -1,9 +1,11 @@ # CUDA Python 11.8.5 Release notes -Released on November 5, 2024 +Released on November 5, 2024. Post 1 rebuild released on November 12, 2024. ## Highlights -- Resolve [Issue #215](https://github.com/NVIDIA/cuda-python/issues/215): module 'cuda.ccudart' has no attribute '__pyx_capi__' +- Resolve [Issue #215](https://github.com/NVIDIA/cuda-python/issues/215): module `cuda.ccudart` has no attribute `__pyx_capi__` +- Resolve [Issue #226](https://github.com/NVIDIA/cuda-python/issues/226): top-level Cython source files not packaged + ## Limitations diff --git a/cuda_bindings/docs/source/release/12.6.2-notes.md b/cuda_bindings/docs/source/release/12.6.2-notes.md index 06fe110b..938b9f5a 100644 --- a/cuda_bindings/docs/source/release/12.6.2-notes.md +++ b/cuda_bindings/docs/source/release/12.6.2-notes.md @@ -1,9 +1,11 @@ # CUDA Python 12.6.2 Release notes -Released on November 5, 2024 +Released on November 5, 2024. Post 1 rebuild released on November 12, 2024. ## Highlights -- Resolve [Issue #215](https://github.com/NVIDIA/cuda-python/issues/215): module 'cuda.ccudart' has no attribute '__pyx_capi__' +- Resolve [Issue #215](https://github.com/NVIDIA/cuda-python/issues/215): module `cuda.ccudart` has no attribute `__pyx_capi__` +- Resolve [Issue #226](https://github.com/NVIDIA/cuda-python/issues/226): top-level Cython source files not packaged + ## Limitations diff --git a/cuda_bindings/docs/versions.json b/cuda_bindings/docs/versions.json index 57fe3420..de97bb1c 100644 --- a/cuda_bindings/docs/versions.json +++ b/cuda_bindings/docs/versions.json @@ -1,4 +1,5 @@ { "latest" : "latest", - "12.6.1" : "12.6.1" + "12.6.1" : "12.6.1", + "12.6.2" : "12.6.2" } diff --git a/cuda_core/cuda/core/experimental/_module.py b/cuda_core/cuda/core/experimental/_module.py index 8b0ff9a7..7621b9ee 100644 --- a/cuda_core/cuda/core/experimental/_module.py +++ b/cuda_core/cuda/core/experimental/_module.py @@ -93,7 +93,7 @@ class ObjectCode: a file path string containing that module for loading. code_type : Any String of the compiled type. - Supported options are "ptx", "cubin" and "fatbin". + Supported options are "ptx", "cubin", "ltoir" and "fatbin". jit_options : Optional Mapping of JIT options to use during module loading. (Default to no options) @@ -105,7 +105,7 @@ class ObjectCode: """ __slots__ = ("_handle", "_code_type", "_module", "_loader", "_sym_map") - _supported_code_type = ("cubin", "ptx", "fatbin") + _supported_code_type = ("cubin", "ptx", "ltoir", "fatbin") def __init__(self, module, code_type, jit_options=None, *, symbol_mapping=None): diff --git a/cuda_core/cuda/core/experimental/_program.py b/cuda_core/cuda/core/experimental/_program.py index 5439c74a..75b7313f 100644 --- a/cuda_core/cuda/core/experimental/_program.py +++ b/cuda_core/cuda/core/experimental/_program.py @@ -26,7 +26,7 @@ class Program: __slots__ = ("_handle", "_backend", ) _supported_code_type = ("c++", ) - _supported_target_type = ("ptx", "cubin", "ltoir", ) + _supported_target_type = ("ptx", "cubin", "ltoir") def __init__(self, code, code_type): self._handle = None diff --git a/cuda_core/docs/source/release/0.1.0-notes.md b/cuda_core/docs/source/release/0.1.0-notes.md index 1ebb41f9..2131ed90 100644 --- a/cuda_core/docs/source/release/0.1.0-notes.md +++ b/cuda_core/docs/source/release/0.1.0-notes.md @@ -1,9 +1,9 @@ # `cuda.core` Release notes -Released on Nov XX, 2024 +Released on Nov 8, 2024 ## Hightlights -- Initial EA1 (early access) release +- Initial beta release - Supports all platforms that CUDA is supported - Supports all CUDA 11.x/12.x drivers - Supports all CUDA 11.x/12.x Toolkits diff --git a/cuda_core/tests/conftest.py b/cuda_core/tests/conftest.py index 3ff6ce08..3c7eccd0 100644 --- a/cuda_core/tests/conftest.py +++ b/cuda_core/tests/conftest.py @@ -5,12 +5,29 @@ # this software. Any use, reproduction, disclosure, or distribution of # this software and related documentation outside the terms of the EULA # is strictly prohibited. +try: + from cuda.bindings import driver +except ImportError: + from cuda import cuda as driver -from cuda.core.experimental._device import Device +from cuda.core.experimental import Device +from cuda.core.experimental import _device +from cuda.core.experimental._utils import handle_return import pytest -@pytest.fixture(scope="module") +@pytest.fixture(scope="function") def init_cuda(): device = Device() device.set_current() - \ No newline at end of file + yield + _device_unset_current() + +def _device_unset_current(): + handle_return(driver.cuCtxPopCurrent()) + with _device._tls_lock: + del _device._tls.devices + +@pytest.fixture(scope="function") +def deinit_cuda(): + yield + _device_unset_current() \ No newline at end of file diff --git a/cuda_core/tests/example_tests/test_basic_examples.py b/cuda_core/tests/example_tests/test_basic_examples.py index e490892d..c02ea43f 100644 --- a/cuda_core/tests/example_tests/test_basic_examples.py +++ b/cuda_core/tests/example_tests/test_basic_examples.py @@ -20,6 +20,6 @@ 'example', sample_files ) class TestExamples: - def test_example(self, example): + def test_example(self, example, deinit_cuda): filename = os.path.basename(example) run_example(samples_path, example) diff --git a/cuda_core/tests/example_tests/utils.py b/cuda_core/tests/example_tests/utils.py index 5f4e14b0..23a3018c 100644 --- a/cuda_core/tests/example_tests/utils.py +++ b/cuda_core/tests/example_tests/utils.py @@ -6,7 +6,6 @@ # this software and related documentation outside the terms of the EULA # is strictly prohibited. -from cuda import cuda import gc import os import sys diff --git a/cuda_core/tests/test_device.py b/cuda_core/tests/test_device.py index 653dac06..c809bfb3 100644 --- a/cuda_core/tests/test_device.py +++ b/cuda_core/tests/test_device.py @@ -6,12 +6,20 @@ # this software and related documentation outside the terms of the EULA # is strictly prohibited. -from cuda import cuda, cudart -from cuda.core.experimental._device import Device -from cuda.core.experimental._utils import handle_return, ComputeCapability, CUDAError, \ - precondition -import pytest +try: + from cuda.bindings import driver, runtime +except ImportError: + from cuda import cuda as driver + from cuda import cudart as runtime +from cuda.core.experimental import Device +from cuda.core.experimental._utils import handle_return, ComputeCapability + +def test_device_set_current(deinit_cuda): + device = Device() + device.set_current() + assert handle_return(driver.cuCtxGetCurrent()) is not None + def test_device_repr(): device = Device(0) assert str(device).startswith('= 11040: - uuid = handle_return(cuda.cuDeviceGetUuid_v2(device.device_id)) + uuid = handle_return(driver.cuDeviceGetUuid_v2(device.device_id)) else: - uuid = handle_return(cuda.cuDeviceGetUuid(device.device_id)) + uuid = handle_return(driver.cuDeviceGetUuid(device.device_id)) uuid = uuid.bytes.hex() expected_uuid = f"{uuid[:8]}-{uuid[8:12]}-{uuid[12:16]}-{uuid[16:20]}-{uuid[20:]}" assert device.uuid == expected_uuid def test_name(): device = Device() - name = handle_return(cuda.cuDeviceGetName(128, device.device_id)) + name = handle_return(driver.cuDeviceGetName(128, device.device_id)) name = name.split(b'\0')[0] assert device.name == name.decode() def test_compute_capability(): device = Device() - major = handle_return(cudart.cudaDeviceGetAttribute( - cudart.cudaDeviceAttr.cudaDevAttrComputeCapabilityMajor, device.device_id)) - minor = handle_return(cudart.cudaDeviceGetAttribute( - cudart.cudaDeviceAttr.cudaDevAttrComputeCapabilityMinor, device.device_id)) + major = handle_return(runtime.cudaDeviceGetAttribute( + runtime.cudaDeviceAttr.cudaDevAttrComputeCapabilityMajor, device.device_id)) + minor = handle_return(runtime.cudaDeviceGetAttribute( + runtime.cudaDeviceAttr.cudaDevAttrComputeCapabilityMinor, device.device_id)) expected_cc = ComputeCapability(major, minor) assert device.compute_capability == expected_cc \ No newline at end of file diff --git a/cuda_core/tests/test_event.py b/cuda_core/tests/test_event.py index b6cfe647..42d1ef95 100644 --- a/cuda_core/tests/test_event.py +++ b/cuda_core/tests/test_event.py @@ -6,34 +6,38 @@ # this software and related documentation outside the terms of the EULA # is strictly prohibited. -from cuda import cuda -from cuda.core.experimental._event import EventOptions, Event -from cuda.core.experimental._utils import handle_return -from cuda.core.experimental._device import Device +from cuda.core.experimental import Device, EventOptions import pytest -def test_is_timing_disabled(): - options = EventOptions(enable_timing=False) - event = Event._init(options) - assert event.is_timing_disabled == True +@pytest.mark.parametrize("enable_timing", [True, False, None]) +def test_timing(init_cuda, enable_timing): + options = EventOptions(enable_timing=enable_timing) + stream = Device().create_stream() + event = stream.record(options=options) + assert event.is_timing_disabled == (not enable_timing if enable_timing is not None else True) + -def test_is_sync_busy_waited(): - options = EventOptions(busy_waited_sync=True) - event = Event._init(options) +def test_is_sync_busy_waited(init_cuda): + options = EventOptions(enable_timing=False, busy_waited_sync=True) + stream = Device().create_stream() + event = stream.record(options=options) assert event.is_sync_busy_waited == True -def test_sync(): - options = EventOptions() - event = Event._init(options) + options = EventOptions(enable_timing=False) + stream = Device().create_stream() + event = stream.record(options=options) + assert event.is_sync_busy_waited == False + +def test_sync(init_cuda): + options = EventOptions(enable_timing=False) + stream = Device().create_stream() + event = stream.record(options=options) event.sync() assert event.is_done == True -def test_is_done(): - options = EventOptions() - event = Event._init(options) +def test_is_done(init_cuda): + options = EventOptions(enable_timing=False) + stream = Device().create_stream() + event = stream.record(options=options) assert event.is_done == True -def test_handle(): - options = EventOptions() - event = Event._init(options) - assert isinstance(event.handle, int) diff --git a/cuda_core/tests/test_launcher.py b/cuda_core/tests/test_launcher.py index 92dfc726..796050a8 100644 --- a/cuda_core/tests/test_launcher.py +++ b/cuda_core/tests/test_launcher.py @@ -6,14 +6,10 @@ # this software and related documentation outside the terms of the EULA # is strictly prohibited. -from cuda import cuda -from cuda.core.experimental._launcher import LaunchConfig -from cuda.core.experimental._stream import Stream -from cuda.core.experimental._device import Device -from cuda.core.experimental._utils import handle_return +from cuda.core.experimental import Device, Stream, LaunchConfig import pytest -def test_launch_config_init(): +def test_launch_config_init(init_cuda): config = LaunchConfig(grid=(1, 1, 1), block=(1, 1, 1), stream=None, shmem_size=0) assert config.grid == (1, 1, 1) assert config.block == (1, 1, 1) @@ -50,7 +46,7 @@ def test_launch_config_invalid_values(): with pytest.raises(ValueError): LaunchConfig(grid=(1, 1, 1), block=(0, 1)) -def test_launch_config_stream(): +def test_launch_config_stream(init_cuda): stream = Device().create_stream() config = LaunchConfig(grid=(1, 1, 1), block=(1, 1, 1), stream=stream, shmem_size=0) assert config.stream == stream diff --git a/cuda_core/tests/test_memory.py b/cuda_core/tests/test_memory.py index 40855268..0a70e52a 100644 --- a/cuda_core/tests/test_memory.py +++ b/cuda_core/tests/test_memory.py @@ -6,12 +6,15 @@ # this software and related documentation outside the terms of the EULA # is strictly prohibited. -from cuda import cuda +try: + from cuda.bindings import driver +except ImportError: + from cuda import cuda as driver + +from cuda.core.experimental import Device from cuda.core.experimental._memory import Buffer, MemoryResource -from cuda.core.experimental._device import Device from cuda.core.experimental._utils import handle_return import ctypes -import pytest class DummyDeviceMemoryResource(MemoryResource): def __init__(self, device): @@ -66,11 +69,11 @@ def __init__(self, device): self.device = device def allocate(self, size, stream=None) -> Buffer: - ptr = handle_return(cuda.cuMemAllocManaged(size, cuda.CUmemAttach_flags.CU_MEM_ATTACH_GLOBAL.value)) + ptr = handle_return(driver.cuMemAllocManaged(size, driver.CUmemAttach_flags.CU_MEM_ATTACH_GLOBAL.value)) return Buffer(ptr=ptr, size=size, mr=self) def deallocate(self, ptr, size, stream=None): - handle_return(cuda.cuMemFree(ptr)) + handle_return(driver.cuMemFree(ptr)) @property def is_device_accessible(self) -> bool: @@ -89,11 +92,11 @@ def __init__(self, device): self.device = device def allocate(self, size, stream=None) -> Buffer: - ptr = handle_return(cuda.cuMemAllocHost(size)) + ptr = handle_return(driver.cuMemAllocHost(size)) return Buffer(ptr=ptr, size=size, mr=self) def deallocate(self, ptr, size, stream=None): - handle_return(cuda.cuMemFreeHost(ptr)) + handle_return(driver.cuMemFreeHost(ptr)) @property def is_device_accessible(self) -> bool: diff --git a/cuda_core/tests/test_module.py b/cuda_core/tests/test_module.py index 7c71804f..83296377 100644 --- a/cuda_core/tests/test_module.py +++ b/cuda_core/tests/test_module.py @@ -6,10 +6,7 @@ # this software and related documentation outside the terms of the EULA # is strictly prohibited. -from cuda import cuda -from cuda.core.experimental._device import Device -from cuda.core.experimental._module import Kernel, ObjectCode -from cuda.core.experimental._utils import handle_return +from cuda.core.experimental._module import ObjectCode import pytest import importlib diff --git a/cuda_core/tests/test_program.py b/cuda_core/tests/test_program.py index 39ce4dc6..caa7369e 100644 --- a/cuda_core/tests/test_program.py +++ b/cuda_core/tests/test_program.py @@ -6,9 +6,8 @@ # this software and related documentation outside the terms of the EULA # is strictly prohibited. -from cuda.core.experimental._program import Program +from cuda.core.experimental import Program from cuda.core.experimental._module import ObjectCode, Kernel -from cuda.core.experimental._device import Device import pytest def test_program_init_valid_code_type(): diff --git a/cuda_core/tests/test_stream.py b/cuda_core/tests/test_stream.py index 6e5acd47..e66b1684 100644 --- a/cuda_core/tests/test_stream.py +++ b/cuda_core/tests/test_stream.py @@ -6,68 +6,69 @@ # this software and related documentation outside the terms of the EULA # is strictly prohibited. -from cuda.core.experimental._stream import Stream, StreamOptions, LEGACY_DEFAULT_STREAM, PER_THREAD_DEFAULT_STREAM, default_stream -from cuda.core.experimental._event import Event, EventOptions -from cuda.core.experimental._device import Device +from cuda.core.experimental import Device, Stream, StreamOptions +from cuda.core.experimental._stream import LEGACY_DEFAULT_STREAM, PER_THREAD_DEFAULT_STREAM, default_stream +from cuda.core.experimental._event import Event import pytest def test_stream_init(): with pytest.raises(NotImplementedError): Stream() -def test_stream_init_with_options(): - stream = Stream._init(options=StreamOptions(nonblocking=True, priority=0)) +def test_stream_init_with_options(init_cuda): + stream = Device().create_stream(options=StreamOptions(nonblocking=True, priority=0)) assert stream.is_nonblocking is True assert stream.priority == 0 -def test_stream_handle(): - stream = Stream._init(options=StreamOptions()) +def test_stream_handle(init_cuda): + stream = Device().create_stream(options=StreamOptions()) assert isinstance(stream.handle, int) -def test_stream_is_nonblocking(): - stream = Stream._init(options=StreamOptions(nonblocking=True)) +def test_stream_is_nonblocking(init_cuda): + stream = Device().create_stream(options=StreamOptions(nonblocking=True)) assert stream.is_nonblocking is True -def test_stream_priority(): - stream = Stream._init(options=StreamOptions(priority=0)) +def test_stream_priority(init_cuda): + stream = Device().create_stream(options=StreamOptions(priority=0)) assert stream.priority == 0 - stream = Stream._init(options=StreamOptions(priority=-1)) + stream = Device().create_stream(options=StreamOptions(priority=-1)) assert stream.priority == -1 with pytest.raises(ValueError): - stream = Stream._init(options=StreamOptions(priority=1)) + stream = Device().create_stream(options=StreamOptions(priority=1)) -def test_stream_sync(): - stream = Stream._init(options=StreamOptions()) +def test_stream_sync(init_cuda): + stream = Device().create_stream(options=StreamOptions()) stream.sync() # Should not raise any exceptions -def test_stream_record(): - stream = Stream._init(options=StreamOptions()) +def test_stream_record(init_cuda): + stream = Device().create_stream(options=StreamOptions()) event = stream.record() assert isinstance(event, Event) -def test_stream_record_invalid_event(): - stream = Stream._init(options=StreamOptions()) +def test_stream_record_invalid_event(init_cuda): + stream = Device().create_stream(options=StreamOptions()) with pytest.raises(TypeError): stream.record(event="invalid_event") -def test_stream_wait_event(): - stream = Stream._init(options=StreamOptions()) - event = Event._init() - stream.record(event) - stream.wait(event) # Should not raise any exceptions +def test_stream_wait_event(init_cuda): + s1 = Device().create_stream() + s2 = Device().create_stream() + e1 = s1.record() + s2.wait(e1) # Should not raise any exceptions + s2.sync() -def test_stream_wait_invalid_event(): - stream = Stream._init(options=StreamOptions()) +def test_stream_wait_invalid_event(init_cuda): + stream = Device().create_stream(options=StreamOptions()) with pytest.raises(ValueError): stream.wait(event_or_stream="invalid_event") -def test_stream_device(): - stream = Stream._init(options=StreamOptions()) +def test_stream_device(init_cuda): + stream = Device().create_stream(options=StreamOptions()) device = stream.device assert isinstance(device, Device) -def test_stream_context(): - stream = Stream._init(options=StreamOptions()) +def test_stream_context(init_cuda): + stream = Device().create_stream(options=StreamOptions()) context = stream.context assert context is not None diff --git a/cuda_python/docs/build_docs.sh b/cuda_python/docs/build_docs.sh index f1dbcbe1..09ed3bbf 100755 --- a/cuda_python/docs/build_docs.sh +++ b/cuda_python/docs/build_docs.sh @@ -3,9 +3,13 @@ set -ex # SPHINX_CUDA_PYTHON_VER is used to create a subdir under build/html -# (the Makefile file for sphinx-build also honors it if defined) +# (the Makefile file for sphinx-build also honors it if defined). +# If there's a post release (ex: .post1) we don't want it to show up in the +# version selector or directory structure. if [[ -z "${SPHINX_CUDA_PYTHON_VER}" ]]; then - export SPHINX_CUDA_PYTHON_VER=$(python -c "from importlib.metadata import version; print(version('cuda-python'))" \ + export SPHINX_CUDA_PYTHON_VER=$(python -c "from importlib.metadata import version; \ + ver = '.'.join(str(version('cuda-python')).split('.')[:3]); \ + print(ver)" \ | awk -F'+' '{print $1}') fi diff --git a/cuda_python/docs/source/release.md b/cuda_python/docs/source/release.md index 7af89792..53a647f5 100644 --- a/cuda_python/docs/source/release.md +++ b/cuda_python/docs/source/release.md @@ -5,5 +5,6 @@ maxdepth: 3 --- + 12.6.2 12.6.1 ``` diff --git a/cuda_python/docs/source/release/12.6.2-notes.md b/cuda_python/docs/source/release/12.6.2-notes.md new file mode 100644 index 00000000..96c90e2a --- /dev/null +++ b/cuda_python/docs/source/release/12.6.2-notes.md @@ -0,0 +1,12 @@ +# CUDA Python Release notes + +Released on November 5, 2024. Post 1 rebuild released on November 12, 2024. + +## Included components + +- [`cuda.bindings` 12.6.2](https://nvidia.github.io/cuda-python/cuda-bindings/12.6.2/release/12.6.2-notes.html) + + +## Hightlights +- Resolve [Issue #215](https://github.com/NVIDIA/cuda-python/issues/215): module `cuda.ccudart` has no attribute `__pyx_capi__` +- Resolve [Issue #226](https://github.com/NVIDIA/cuda-python/issues/226): top-level Cython source files not packaged diff --git a/cuda_python/docs/versions.json b/cuda_python/docs/versions.json index 57fe3420..de97bb1c 100644 --- a/cuda_python/docs/versions.json +++ b/cuda_python/docs/versions.json @@ -1,4 +1,5 @@ { "latest" : "latest", - "12.6.1" : "12.6.1" + "12.6.1" : "12.6.1", + "12.6.2" : "12.6.2" }