diff --git a/cuda_bindings/cuda/bindings/_example_helpers/common.py b/cuda_bindings/cuda/bindings/_example_helpers/common.py index 6335d3e3e4a..2871eee689d 100644 --- a/cuda_bindings/cuda/bindings/_example_helpers/common.py +++ b/cuda_bindings/cuda/bindings/_example_helpers/common.py @@ -21,6 +21,19 @@ def requirement_not_met(message): return sys.exit(int(exitcode)) +#: NVRTC gained cubin output (nvrtcGetCUBIN) in CUDA 11.1. +NVRTC_CUBIN_MIN_VERSION = (11, 1) + + +def nvrtc_supports_cubin(nvrtc_version): + """Whether this NVRTC can emit cubin rather than only PTX. + + Compares (major, minor) as a tuple: looking at the minor alone reports + "no cubin" for every x.0 release, e.g. NVRTC 12.0 and 13.0. + """ + return tuple(nvrtc_version) >= NVRTC_CUBIN_MIN_VERSION + + def check_compute_capability_too_low(dev_id, required_cc_major_minor): cc_major = check_cuda_errors( cudart.cudaDeviceGetAttribute(cudart.cudaDeviceAttr.cudaDevAttrComputeCapabilityMajor, dev_id) @@ -55,8 +68,7 @@ def __init__(self, code, dev_id): minor = check_cuda_errors( cudart.cudaDeviceGetAttribute(cudart.cudaDeviceAttr.cudaDevAttrComputeCapabilityMinor, dev_id) ) - _, nvrtc_minor = nvrtc.version() - use_cubin = nvrtc_minor >= 1 + use_cubin = nvrtc_supports_cubin(nvrtc.version()) prefix = "sm" if use_cubin else "compute" arch_arg = bytes(f"--gpu-architecture={prefix}_{major}{minor}", "ascii") diff --git a/cuda_bindings/examples/extra/jit_program.py b/cuda_bindings/examples/extra/jit_program.py index 7a5cc1495fc..e40c703a6ea 100644 --- a/cuda_bindings/examples/extra/jit_program.py +++ b/cuda_bindings/examples/extra/jit_program.py @@ -68,8 +68,10 @@ def main(): cuda.CUdevice_attribute.CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, cu_device ) assert_drv(err) - nvrtc_major, nvrtc_minor = nvrtc.version() - use_cubin = nvrtc_minor >= 1 + # NVRTC gained cubin output in CUDA 11.1. Compare (major, minor) as a + # tuple: looking at the minor alone reports "no cubin" for every x.0 + # release, e.g. NVRTC 12.0 and 13.0. + use_cubin = nvrtc.version() >= (11, 1) prefix = "sm" if use_cubin else "compute" arch_arg = bytes(f"--gpu-architecture={prefix}_{major}{minor}", "ascii") diff --git a/cuda_bindings/tests/test_kernel_helper.py b/cuda_bindings/tests/test_kernel_helper.py new file mode 100644 index 00000000000..aecf47505ae --- /dev/null +++ b/cuda_bindings/tests/test_kernel_helper.py @@ -0,0 +1,32 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +import pytest + +from cuda.bindings._example_helpers.common import nvrtc_supports_cubin + + +@pytest.mark.agent_authored(model="claude-opus-5") +@pytest.mark.parametrize( + ("nvrtc_version", "expected"), + [ + ((11, 0), False), # predates nvrtcGetCUBIN + ((11, 1), True), # the release that added it + ((11, 8), True), + ((12, 0), True), # x.0 releases: minor alone would say False + ((12, 9), True), + ((13, 0), True), + ((13, 4), True), + ], +) +def test_nvrtc_supports_cubin(nvrtc_version, expected): + assert nvrtc_supports_cubin(nvrtc_version) is expected + + +@pytest.mark.agent_authored(model="claude-opus-5") +@pytest.mark.parametrize("nvrtc_version", [(12, 0), (13, 0)]) +def test_minor_only_check_would_be_wrong_for_x_0_releases(nvrtc_version): + """Pins the exact regression: `nvrtc_minor >= 1` disagrees on every x.0.""" + _, nvrtc_minor = nvrtc_version + assert (nvrtc_minor >= 1) is False + assert nvrtc_supports_cubin(nvrtc_version) is True