Skip to content

Revert nvJitLink driver-major compatibility fallback#2355

Open
isVoid wants to merge 3 commits into
NVIDIA:mainfrom
isVoid:agent/revert-pr-2320
Open

Revert nvJitLink driver-major compatibility fallback#2355
isVoid wants to merge 3 commits into
NVIDIA:mainfrom
isVoid:agent/revert-pr-2320

Conversation

@isVoid

@isVoid isVoid commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Summary

Rationale

The backend-selection policy and the cuLink storage-lifetime fix are independent. This change rolls back the compatibility fallback while preserving the memory-safety fix that keeps storage referenced by CUlinkState alive until cuLinkDestroy.

User impact

cuda.core will use nvJitLink whenever it is available and exposes the required version symbol, even when the CUDA driver has a newer major version. When the cuLink backend is used, its option arrays and log buffers remain valid for the full lifetime of the link state.

Testing

  • pixi run --frozen -e cu13 pytest tests/test_linker.py tests/test_optional_dependency_imports.py tests/test_program_cache.py -q (278 passed, 4 skipped)
  • git diff --check upstream/main...HEAD

Partially reverts #2320.

@isVoid isVoid added this to the cuda.core next milestone Jul 14, 2026
@isVoid isVoid added bug Something isn't working cuda.core Everything related to the cuda.core module labels Jul 14, 2026
@copy-pr-bot

copy-pr-bot Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

@isVoid isVoid self-assigned this Jul 14, 2026
@isVoid isVoid added the P0 High priority - Must do! label Jul 14, 2026
@isVoid isVoid marked this pull request as ready for review July 14, 2026 18:12
@isVoid isVoid changed the title Revert "Check nvJitLink driver major compatibility" Revert nvJitLink driver-major compatibility fallback Jul 14, 2026
@github-actions

Copy link
Copy Markdown

@leofang leofang left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. The inline comments below are nitpicks about tests for the cuLink backend path, which does not appear to have CI coverage today — feel free to defer.

-- Leo's bot

Comment thread cuda_core/tests/test_linker.py Outdated
Comment on lines +200 to +212
def test_linker_options_as_bytes_invalid_backend():
"""Test LinkerOptions.as_bytes() with invalid backend"""
options = LinkerOptions(arch="sm_80")
with pytest.raises(ValueError, match="only supports 'nvjitlink' backend"):
options.as_bytes(backend)
options.as_bytes("invalid")


@pytest.mark.skipif(not is_culink_backend, reason="driver backend test")
def test_linker_options_as_bytes_driver_not_supported():
"""Test that as_bytes() is not supported for driver backend"""
options = LinkerOptions(arch="sm_80")
with pytest.raises(RuntimeError, match="as_bytes\\(\\) only supports 'nvjitlink' backend"):
options.as_bytes("driver")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: this resurrects a pre-#2320 test bug: as_bytes("driver") raises ValueError (the backend-string check fires before the availability check), so pytest.raises(RuntimeError) won't catch it — the test fails whenever it isn't skipped:

backend = backend.lower()
if backend != "nvjitlink":
raise ValueError(f"as_bytes() only supports 'nvjitlink' backend, got '{backend}'")
if not _use_nvjitlink_backend:
raise RuntimeError("nvJitLink backend is not available")

#2320's parametrization was correct on both backends:

Suggested change
def test_linker_options_as_bytes_invalid_backend():
"""Test LinkerOptions.as_bytes() with invalid backend"""
options = LinkerOptions(arch="sm_80")
with pytest.raises(ValueError, match="only supports 'nvjitlink' backend"):
options.as_bytes(backend)
options.as_bytes("invalid")
@pytest.mark.skipif(not is_culink_backend, reason="driver backend test")
def test_linker_options_as_bytes_driver_not_supported():
"""Test that as_bytes() is not supported for driver backend"""
options = LinkerOptions(arch="sm_80")
with pytest.raises(RuntimeError, match="as_bytes\\(\\) only supports 'nvjitlink' backend"):
options.as_bytes("driver")
@pytest.mark.parametrize("backend", ("invalid", "driver"))
def test_linker_options_as_bytes_invalid_backend(backend):
"""Test LinkerOptions.as_bytes() with invalid backend"""
options = LinkerOptions(arch="sm_80")
with pytest.raises(ValueError, match="only supports 'nvjitlink' backend"):
options.as_bytes(backend)

Comment on lines +374 to +376
# ``time`` is a presence gate: the linker emits ``-time`` for any
# non-None value, so True / "path" produce the same flag.
pytest.param({"time": True}, {"time": "timing.csv"}, id="time_true_eq_path"),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: on a cuLink-backend host, _LinkerBackend.validate() rejects non-None time, so this case fails there:

if self._decide_driver() is True:
# Mirror ``_prepare_driver_options``'s exact gate: ``is not
# None`` for these fields, so ``time=False`` or
# ``ptxas_options=[]`` is still a rejection. Do NOT use the
# truthiness-based ``_option_is_set`` helper here.
unsupported = [
name for name in _DRIVER_LINKER_UNSUPPORTED_FIELDS if getattr(options, name, None) is not None
]
if unsupported:
raise ValueError(
f"the cuLink driver linker does not support these options: "
f"{', '.join(unsupported)}; Program.compile() would reject this "
f"configuration before producing an ObjectCode."
)

The monkeypatch in this test only pins the version probe, not the backend decision. Pinning the decision too (same idiom as test_make_program_cache_key_ptx_driver_ignored_fields_collapse) keeps the case portable:

    from cuda.core import _linker

    monkeypatch.setattr(_linker, "_decide_nvjitlink_or_driver", lambda: False)  # nvJitLink

Comment on lines 1004 to 1007
def test_make_program_cache_key_accepts_side_effect_options_for_ptx(option_kw):
"""nvJitLink ``-time`` writes only to its info log, not the filesystem."""
"""The side-effect guard is NVRTC-specific: PTX (linker) and NVVM must
not be blocked by options whose side effects only apply under NVRTC."""
_make_key(code=".version 7.0", code_type="ptx", options=_opts(**option_kw)) # no raise

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: same as the comment above — without the skipif, time_true/time_path hit the driver-unsupported-options rejection on cuLink hosts. Pinning the backend avoids both the failure and the skip:

Suggested change
def test_make_program_cache_key_accepts_side_effect_options_for_ptx(option_kw):
"""nvJitLink ``-time`` writes only to its info log, not the filesystem."""
"""The side-effect guard is NVRTC-specific: PTX (linker) and NVVM must
not be blocked by options whose side effects only apply under NVRTC."""
_make_key(code=".version 7.0", code_type="ptx", options=_opts(**option_kw)) # no raise
def test_make_program_cache_key_accepts_side_effect_options_for_ptx(option_kw, monkeypatch):
"""The side-effect guard is NVRTC-specific: PTX (linker) and NVVM must
not be blocked by options whose side effects only apply under NVRTC."""
from cuda.core import _linker
monkeypatch.setattr(_linker, "_decide_nvjitlink_or_driver", lambda: False) # nvJitLink
_make_key(code=".version 7.0", code_type="ptx", options=_opts(**option_kw)) # no raise

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working cuda.core Everything related to the cuda.core module P0 High priority - Must do!

Projects

None yet

Development

Successfully merging this pull request may close these issues.

cuda.core Linker rejects LTO-IR (regression from #2320): falls back to cuLink* when CUDA driver major > nvJitLink major

2 participants