Skip to content

Continue merging main into 13.4.x - #2641

Draft
rwgk wants to merge 55 commits into
NVIDIA:13.4.x-merge-main-2026-08-10+0131from
rwgk:13.4.x-merge-main-cont
Draft

Continue merging main into 13.4.x#2641
rwgk wants to merge 55 commits into
NVIDIA:13.4.x-merge-main-2026-08-10+0131from
rwgk:13.4.x-merge-main-cont

Conversation

@rwgk

@rwgk rwgk commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

EDIT (for my own reference mostly): I'm freezing this PR after the internal 530 was merged.


Description

Follow-up to #2588.

Merge the newer public main history into the 13.4.x release line on top of the baseline established by #2588.

This continuation also repairs merge accidents exposed by the initial CI run:

  • temporarily skips the pixi CUDA-version check because CUDA 13.4 Conda packages are not yet available;
  • regenerates the CUDA 13.4.0 bindings with the current cybind generator fixes while preserving the 13.4 API surface;
  • avoids aggregate CUmemLocation initialization now that CUDA 13.4 adds the localized member; and
  • regenerates the merged cuda.core stubs.

The 13.4.x-merge-main-cont branch is intentionally also pushed to the upstream repository so it can serve as the base for another main-merge continuation stacked on top of this PR.

Testing

  • CUDA 13.4 bindings/core build runbook
  • CUDA 13.4 pathfinder, bindings default-stream and PTDS, bindings Cython, cuda.core, and cuda.core Cython test runbooks
  • generated-file seals and cuda.core stub generation
  • pre-commit suite, including Ruff, mypy, actionlint, Cython lint, YAML, and secret scanning

Checklist

  • New or existing tests cover these changes.
  • The documentation is up to date with these changes.

gmanal and others added 30 commits August 11, 2026 14:11
…VIDIA#2589)

Call the centrally maintained NVIDIA/security-workflows security suite rather
than wiring each scan separately: one pinned reference runs the Pulse secret
scan and CodeQL SAST, both explicitly enabled.

Replace .github/workflows/codeql.yml with the suite's SAST scan. Both publish
code scanning results under the category /language:python, so keeping the local
workflow would put two analyses on every commit that overwrite each other's
alerts. The suite performs the same analysis: python, build-mode none,
security-extended queries, on ubuntu-latest.
* fix(cuda.core): avoid truncating graph queries

* perf(cuda.core): retain adjacency stack buffer

* test(cuda.core): cover large predecessor graph queries

Verify exact edge identities so graph query regressions cannot pass through count-only checks.

---------

Co-authored-by: Andy Jost <ajost@nvidia.com>
* Fix Windows binary utility discovery on Arm64

* Clarify binary utility search order

* Expand standalone installation documentation

* Align standalone search step comments

* Preserve literal Nsight launcher lookup

* Cover Windows binary discovery fallbacks

* Document Windows architecture selection

* Harden Windows Arm64 utility discovery

* Fix Windows pre-commit checks

* Fix CUDA path precedence documentation

* Document Windows binary utility discovery

---------

Co-authored-by: Michael Wang <isVoid@users.noreply.github.com>
Co-authored-by: Ralf W. Grosse-Kunstleve <rgrossekunst@nvidia.com>
…VIDIA#2493)

* Migrate _static_libs finders from os.path to pathlib

Part 2 of the series proposed in NVIDIA#2410, following the same conversion
style as part 1 (NVIDIA#2489).

Path construction, joining, and filesystem predicates in
find_static_lib.py and find_bitcode_lib.py now go through pathlib.Path
instead of os.path string manipulation. Both modules keep importing os
solely for os.environ.get("CONDA_PREFIX").

Compatibility is preserved: every entry point still accepts str, and
every function that documents or returns str still returns str. Path is
used strictly as the internal representation and converted back with
str() at each return, so LocatedStaticLib.abs_path, LocatedBitcodeLib
.abs_path, find_static_lib() and find_bitcode_lib() are unchanged in
both type and value. No signature changes.

Signed-off-by: LeSingh1 <sshaurya914@gmail.com>

* Return Path from the _static_libs internals

Follow-up to the review feedback on NVIDIA#2489: the str-compatibility constraint
applies only to the public API.

The try_* methods and _no_such_file_in_dir now work in Path throughout. str()
is applied once, where abs_path is stored on the public LocatedStaticLib and
LocatedBitcodeLib. The relative-path constants go from os.path.join(...) to
forward-slash literals, matching how site_packages_dirs is already written in
the same dicts; Path normalizes the separator on Windows.

One behavior change: a CUDA_PATH or CONDA_PREFIX containing redundant
separators ("//", "/.") now produces a normalized abs_path, because Path
collapses them. Differential fuzzing against the pre-revision code (16k lookups
over randomized trees, comparing located paths and full error text) shows no
other difference, and none at all when those variables are free of redundant
separators.

Signed-off-by: LeSingh1 <sshaurya914@gmail.com>

---------

Signed-off-by: LeSingh1 <sshaurya914@gmail.com>
Co-authored-by: Michael Droettboom <mdboom@gmail.com>
* chore: fix Apache-2.0 license notice and attribution gaps

An open-source license review flagged several Apache-2.0 compliance gaps.
This addresses three of them, plus the guard that let one class of them
through. Licensing metadata only; no logic changes.

Copyright notices (15 files)
  Two different defects that happened to share a symptom:
  - 14 files under cuda_bindings/examples/ carried a non-standard notice
    ("Copyright 2021-2026 NVIDIA Corporation.  All rights reserved.") with
    no (c), no SPDX-FileCopyrightText prefix, and the wrong entity casing.
  - toolshed/conda_create_for_pathfinder_testing.ps1 had the correct prefix
    and casing but was truncated before "& AFFILIATES. All rights reserved.".
  All now carry the canonical string. Years are preserved as found.

Header guard (toolshed/check_spdx.py)
  COPYRIGHT_REGEX made "& AFFILIATES. All rights reserved." optional, so a
  bare "NVIDIA CORPORATION" satisfied pre-commit. The suffix is now
  required. (The 14 example files were passing for a different reason:
  .spdx-ignore excludes cuda_bindings/examples/ entirely. That exclusion is
  left alone here, but the files now conform, so it can be dropped in a
  follow-up if desired.)

  Tightening the regex surfaced two pre-existing files whose notice was
  split or truncated -- cuda_core/cuda/core/_include/layout.hpp and
  toolshed/build_static_bitcode_input.py. Both are corrected so the
  mandated sentence appears verbatim on one line.

Third-party attribution (cuda_core/NOTICE)
  cuda/core/_include/aoti_shim.h is a vendored subset of PyTorch's AOT
  Inductor stable C ABI, BSD-3-Clause, carrying the upstream Facebook,
  Idiap, Deepmind, NEC and NYU copyright lines, but NOTICE listed only
  DLPack. A PyTorch entry is added with the full copyright block. The
  accompanying aoti_shim.def carries no copyright line of its own and is
  covered explicitly by that entry rather than given an NVIDIA header,
  since it declares the same upstream symbol names. The DLPack entry now
  also records where it is vendored.

LICENSE files (all five)
  Every LICENSE ended at "END OF TERMS AND CONDITIONS", omitting the
  required "APPENDIX: How to apply the Apache License to your work" and
  its boilerplate. Appended to all five. The text is verified identical
  to the canonical Apache 2.0 appendix.

Verified: 0 files with a non-conforming copyright string; check_spdx.py
passes over all 868 in-scope tracked files with the tightened regex.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Rob Parolin <rparolin@nvidia.com>

* docs: document per-subproject license files in root README

OSRB (NVBUG 4707569, comment NVIDIA#22) flagged the four sub-component LICENSE
files as redundant with the root LICENSE and asked for either their removal
or a root README Licensing section naming each subproject, its license and
its license path.

Each subproject builds an independent wheel and resolves its license file
relative to its own root, so the copies are kept and documented instead of
removed. Verified that the copies reach the built wheels: building
cuda_pathfinder produces dist-info/licenses/LICENSE even though its
pyproject.toml declares no explicit license-files (setuptools' default
LICEN[CS]E* glob covers it), as is also the case for cuda_core.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Signed-off-by: Rob Parolin <rparolin@nvidia.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…NVIDIA#2496)

* Migrate toolshed and ci helper scripts from os.path to pathlib

Part 7 of the series proposed in NVIDIA#2410.

Path joining and filesystem predicates in the toolshed and ci/tools helper
scripts now go through pathlib. glob.glob in dump_cutile_b64.py becomes
Path.glob, with the mtime key reading Path.stat().

Kept on os.path, with a comment where it is not obvious:

- os.path.abspath in build_static_bitcode_input.py, since sys.path wants a str
  and Path.absolute() does not normalize.
- os.path.isfile in check_generated_file_seals.py. That guard exists to skip
  anything that is not a readable regular file, and Path.is_file() is not a
  drop-in: it propagates OSError for errnos outside pathlib's ignore list
  (EACCES, ENAMETOOLONG) where os.path.isfile returns False.
- os.path.normpath in check_spdx.py, which already carries its own comment.

The plan on NVIDIA#2410 also listed a root conftest.py; there is no such file. The
three conftest.py files live under cuda_pathfinder, cuda_core and
cuda_bindings, and none of them use os.path.

Verified locally: ci/tools/tests/test_check_release_notes.py passes (42
tests), and check_spdx.py and check_generated_file_seals.py produce output
identical to the pre-change scripts when run over every tracked .py file.

Signed-off-by: LeSingh1 <sshaurya914@gmail.com>

* Return Path from notes_path; use Path.is_file in seal checker

Per review: treat these helper scripts as private, so notes_path can return
Path and drop the str/Path round-trip at its call site. Accept the behavioral
change from os.path.isfile to Path.is_file in check_generated_file_seals.

* Review: thread Path through check_release_notes, drop remaining os.path

Follow-up to mdboom's review.

- repo_root is now a Path end to end: load_backport_branch, check_release_notes
  and validate_backport_decision take Path, and --repo-root parses with
  type=Path. That removes the Path(repo_root) re-wrap inside the functions and
  the 19 str(tmp_path) conversions the tests needed to call them. The five
  main() argv lists keep str(): those are command-line strings, which argparse
  then turns back into a Path.
- build_static_bitcode_input: the last os.path use (os.path.abspath) becomes
  Path.resolve(); the os import is now unused and is dropped.

---------

Signed-off-by: LeSingh1 <sshaurya914@gmail.com>
Co-authored-by: Michael Droettboom <mdboom@gmail.com>
def supportsCudaAPI(name):
        return name in dir(cuda) or dir(cudart)

parses as `(name in dir(cuda)) or dir(cudart)`. `dir(cudart)` is a non-empty
list for any module, so it is unconditionally truthy and the function returns
a truthy value for every input, including names that exist nowhere.

The left operand is dead too: `cuda` is cuda.bindings.driver and every name
passed in is a cudaXxx runtime symbol. cudaGraphGetId, cudaGreenCtxCreate,
cudaDeviceGetExecutionCtx and cudaGraphConditionalHandleCreate are all defined
in runtime.pyx and appear nowhere in driver.pyx, so `name in dir(cuda)` is
always False and the result is always the `dir(cudart)` list.

Consequence: `not supportsCudaAPI(...)` is always False, so the API-presence
half of all 17 skipif guards that use it (lines 1443-1954) never fires. On a
build whose bindings genuinely lack the API, the test runs and dies with
AttributeError instead of skipping; only the driver_version_less_than() half
of each guard does any work.

Adds test_supportsCudaAPI, pinning all three cases: a runtime-only name, a
driver-only name, and a name that exists in neither. The last two fail before
this change.
* Catch up to current cybind main

* Bugfix for get_buffer_pointer
…VIDIA#2560)

def supports_nvlink(device):
        fields = nvml.FieldValue(1)
        fields[0].field_id = nvml.FI.DEV_NVLINK_GET_STATE

There is no `FI` attribute on cuda.bindings.nvml. The enum is `FieldId`
(nvml.pyx:1229), with DEV_NVLINK_GET_STATE at nvml.pyx:1454, and the sibling
test uses the correct spelling: test_nvlink.py:19 does
`fields[0].field_id = nvml.FieldId.DEV_NVLINK_LINK_COUNT`.

So the helper raises AttributeError on its first line of real work. Nobody
has noticed because it has no callers -- a repo-wide grep for
`supports_nvlink` finds only its own definition. Contrast util.supports_ecc,
which is called from test_page_retirement.py.

Adds tests/nvml/test_util.py, which stubs nvml.device_get_field_values so the
helper can be exercised without an NVLink-capable device, and asserts both
that it returns True and that it queried FieldId.DEV_NVLINK_GET_STATE. It
fails with AttributeError before this change.
…lue (NVIDIA#2535)

`cuda/core/__init__.py` reads `CUDA_CORE_DONT_FIX_TAB_COMPLETION` with a
bare `int(os.environ.get(..., "0"))` at import time. `int()` raises for any
value that is not a base-10 integer, and `os.environ.get` returns the empty
string (not the `"0"` default) when the variable is set but empty, so:

    export CUDA_CORE_DONT_FIX_TAB_COMPLETION=
    python -c "import cuda.core"
    ValueError: invalid literal for int() with base 10: ''

Clearing a variable with `export VAR=` is the usual way to neutralize it in
a shell profile, a Dockerfile, or a CI job spec, and `=true` / `=yes` are
the obvious guesses for a boolean-looking opt-out. All of them make the
whole package unimportable, which is a hard failure for a knob whose only
purpose is to skip an optional `rlcompleter` patch.

Parse the value leniently instead. Integer values keep their existing
meaning (non-zero opts out, so `0` and `00` still install the patch), while
a non-integer, non-empty value is honored as an opt-out rather than being
silently ignored. Unset and empty/whitespace-only both mean "not set".

Also document the variable, which was not listed on the environment
variables page, and drop the stale "only installed in interactive mode"
comment: the interactivity gate was intentionally removed in NVIDIA#2055 ("Always
install the monkeypatch"), so the patch has been unconditional since then.

The new parametrized test asserts the resulting behavior for eight values;
four of them ("", "   ", "true", "yes") fail on main because the subprocess
exits non-zero with the ValueError above.

Co-authored-by: Michael Droettboom <mdboom@gmail.com>
Docstrings across cuda_core still spelled parameter types with the
pre-3.10 typing generics. Replace Union[...] and Optional[...] with the
| form the rest of the package already uses, e.g. `stream : Stream |
None, optional` in _memoryview.pyx.

Docstrings only, so the .pyi changes are the stubgen-pyx output for the
edited .pyx files and no runtime behavior moves. In _module.pyx this also
realigns the max_potential_block_size docstring with its signature, which
already reads int | driver.CUoccupancyB2DSize.

Two code-level spellings stay as they are:

- LinkerHandleT in _linker.pyx is a runtime value, not an annotation.
  _program.pyx builds ProgramHandleT from it with `nvrtc.nvrtcProgram |
  int | LinkerHandleT`, and PEP 604 `|` on the forward-reference strings
  it holds raises TypeError.
- The union_type literal in _process_define_macro is error-message text
  rather than a docstring.

Sequence[...] and Iterable[...] elsewhere in cuda_core are
collections.abc generics and are unaffected.

Signed-off-by: Aryan <aryansputta@gmail.com>
Co-authored-by: Michael Droettboom <mdboom@gmail.com>
* Use subtests where appropriate everywhere

* Fix test

* Test every fan in a separate subtest

* Recognize skipped pytest subtests in CI logs

* Isolate independent inner test cases

* Narrow the cooler unsupported-call scope

* Contain fan-count failures per device

* Use stable identifiers for device subtests

* Fold nested subtest context managers

* Preserve the existing power-limit getter guard

* Guard memory affinity on pre-Kepler devices

* Keep invalid subtest results contained

---------

Co-authored-by: Ralf W. Grosse-Kunstleve <rgrossekunst@nvidia.com>
* Update PR guidance for organization-owned forks

* Clarify agent remote-write policy

* Add fork-aware pull request skill
…handle (NVIDIA#2551)

get_cuda_native_handle() wraps both the registry lookup and the getter call
in one try:

    try:
        return _handle_getters[obj_type](obj)
    except KeyError:
        raise TypeError("Unknown type: " + str(obj_type)) from None

The except clause is meant for "this type has no registered getter", but it
also fires for a KeyError raised *inside* the getter. When that happens the
diagnosis is wrong twice over: the reported type is registered, and
`from None` suppresses the context so the traceback that would show the real
failure is gone.

    >>> _add_cuda_native_handle_getter(Registered, getter_that_raises_keyerror)
    >>> get_cuda_native_handle(Registered())
    TypeError: Unknown type: <class 'Registered'>

Move the getter call out of the try. The unregistered-type path is
unchanged, which the existing test_get_handle_error still covers.
…IA#2563)

discover_benchmarks() goes out of its way to avoid def-time binding, and
says so:

    # Resolve the default inside the call so tests (and embedders) can
    # monkeypatch ``BENCH_DIR`` at the module level - Python binds default
    # args at def-time, so a literal default would ignore later patches.
    if bench_dir is None:
        bench_dir = BENCH_DIR

main() then reintroduces exactly that binding:

    def main(
        *,
        bench_dir: Path = BENCH_DIR,
        default_output: Path = DEFAULT_OUTPUT,
        ...
        registry = discover_benchmarks(bench_dir=bench_dir, ...)

Because main() always passes a non-None bench_dir down, the sentinel branch
in discover_benchmarks() can never be taken on this path, and patching
runner.main.BENCH_DIR - the documented mechanism - has no effect on main().
Same for DEFAULT_OUTPUT.

run_pyperf.py calls main() with no arguments, so this is the production
path. The existing tests patch BENCH_DIR and call discover_benchmarks()
directly, which is why the gap is invisible today.

Apply the same sentinel to both parameters. Explicit arguments keep working
unchanged, so the embedder API is unaffected.

Adds test_main_honors_a_monkeypatched_bench_dir, which patches BENCH_DIR to a
tmp dir holding one bench_*.py and drives main() with --list. It fails before
this change (main() lists the repo's real benchmarks instead).
* cuda.core: Add copy_batch to cuda.core.utils

* fallback for CUDA 12 and type annotations

* be more precise about CUDA requirements

* skip tests on Windows that require managed memory

* rework some tests

* Deduplicate _to_cumemlocation

* add missing file

* address review feedback

* review feedback: don't assume NUMA capabilities

* review feedback: clarify buffer requirements for async batched copies

* review feedback: explicitly reject special default streams

* review feedback: explicitly reject capturing streams

* review feedback: drop warning about unsupported PREFER_OVERLAP_WITH_COMPUTE hint

* review feedback: add missing descriptions for copy options values

* review feedback: align CopyOptions validation with existing practice

* review feedback: drop conditional imports for type checking

* account for CUDA 12/13 driver differences

* CUDA 12: drop rejection of unsupported copy options

* simplify tests
…or (NVIDIA#2463)

* fix(cuda.bindings): make cythonization warning-clean and enable -Werror

Clear the Cython warnings that blocked matching cuda.core's warning_errors
setting (NVIDIA#2450): drop ignored except clauses on Python-returning cudla
cpdefs, declare LOAD_LIBRARY_SEARCH_SYSTEM32 as const in windll.pxd, and
enable Cython Options.warning_errors in build_hooks.

Add source-level regression tests so these patterns do not return.

Signed-off-by: Omar Atie <atiaomar1978-hub@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

* style: ruff-format cython warning cleanliness tests

Signed-off-by: Omar Atie <atiaomar1978-hub@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

* test(cuda.bindings): drop cython warning cleanliness tests

Address review feedback: warning_errors in build_hooks already
guards against Cython warning regressions, so the source-level
tests add unnecessary maintenance cost.

Signed-off-by: Omar Atie <atiaomar1978-hub@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Signed-off-by: Omar Atie <atiaomar1978-hub@users.noreply.github.com>
Co-authored-by: Omar Atie <atiaomar1978-hub@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…ed (NVIDIA#2539)

`check_generated_file_seals.py` declares three comment styles for the seal
line, one per generated-file family:

    _COMMENT_CHARS = {".py": b"#", ..., ".rst": b"..", ".c": b"//",
                      ".cpp": b"//", ".h": b"//"}

and `validate_generated_file_seal` compares the seal's captured prefix
against `expected_comment_prefix(filepath)` so a `.rst` file cannot be
sealed with a `#`, and so on. But the marker regex only ever accepts two of
the three:

    rb"^(?P<prefix>#|\.\.) "

`//` can never be captured, so `fullmatch` returns None for any sealed
`.c` / `.cpp` / `.h` file and it is rejected as `MALFORMED generated-file
seal` before the prefix comparison runs at all. The `b"//"` entries in
`_COMMENT_CHARS` and the branch that would validate them are dead.

Add `//` to the alternation, with a note tying it to `_COMMENT_CHARS` so
the two do not drift again.

This also adds the first tests for the script, under `toolshed/tests/`, and
runs them alongside the existing `ci/tools/tests` in the nightly tooling
job. The parametrized case is driven from `_COMMENT_CHARS` itself, so a
future entry whose prefix the regex cannot match fails immediately instead
of silently becoming dead code.
…VIDIA#2526)

* cuda.core: capture bound contexts for buffer deallocation streams

Record a DeallocationStream at device-pointer creation so default-stream tokens pin the allocation context (and PTDS the allocating thread) instead of relying on ambient state at free time.

* cuda.core: activate bound context during device-pointer teardown

Make the deallocation stream's context current around free/unmap/MR cleanup so destruction no longer depends on ambient CUDA context, and wire cuCtxSetCurrent into the resource-handles driver table.

* cuda.core: record from_handle deallocation streams at creation

Add keyword-only stream= on Buffer/ManagedBuffer.from_handle when mr owns the pointer, bind it at construction, and cover teardown with no or foreign current context.

* cuda.core: fail loudly on MemoryResource free errors

Stop treating CUDA_ERROR_INVALID_CONTEXT as a successful pool free, and let
explicit mr.deallocate() raise; destruction still contains errors in the
callback. Document PTDS deallocation ordering on the stream parameters and
note the context-safe Buffer teardown fix in the 1.2.0 release notes.

* cuda.core: reject incomplete buffer deallocation recipes

Require default deallocation streams to bind a current context at creation so teardown never relies on an ambiguous ambient token. Expand coverage and documentation for context-independent cleanup and failure reporting.

* cuda.core: initialize context when unpickling IPC buffers

Ensure spawned children can bind the imported buffer's default deallocation stream before their process target starts.

* test(cuda.core): set a current context in DLPack failure tests

Creating a Buffer with an owning memory resource now records a default
deallocation stream, which requires a current context. These two tests
never set one, so they passed or failed depending on whether the
preceding test left a context current under pytest-randomly.

* test(cuda.core): address review feedback on deallocation-stream PR

- Parametrize test_from_handle_mr_records_default_stream,
  test_from_handle_mr_records_explicit_stream, and
  test_from_handle_stream_requires_mr with [Buffer, ManagedBuffer] to
  cover the ManagedBuffer.from_handle entry point directly.
- Add test_close_with_default_stream_requires_context covering the
  _require_deallocation_stream_context guard in Buffer_close.
- Lift Stream_accept and default_stream to module-level imports.
- Replace _require_deallocation_stream_context (a pre-flight that
  duplicated make_deallocation_stream's context check) with
  _apply_deallocation_stream, which calls set_deallocation_stream once
  and translates CUDA_ERROR_INVALID_CONTEXT into a descriptive
  RuntimeError. Removes the redundant cuCtxGetCurrent call on the
  default-stream success path.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…#2618)

* cuda.core: minor refactoring to prepare for copy with options

* inline capability check helper
* ci: add selective wheel test plumbing

* ci: update selective wheel test callers

* ci: enable nightly NumPy for metapackage tests

* ci: install exact local wheels in metapackage tests

* ci: simplify local wheel selection
…ont-update-2026-08-14

# Conflicts:
#	.github/workflows/build-wheel.yml
#	.github/workflows/test-sdist-linux.yml
#	.github/workflows/test-sdist-windows.yml
#	cuda_bindings/cuda/bindings/_internal/cudla.pxd
#	cuda_bindings/cuda/bindings/_internal/cudla_linux.pyx
#	cuda_bindings/cuda/bindings/_internal/cudla_windows.pyx
#	cuda_bindings/cuda/bindings/_internal/driver_linux.pyx
#	cuda_bindings/cuda/bindings/_internal/driver_windows.pyx
#	cuda_bindings/cuda/bindings/_internal/nvfatbin_linux.pyx
#	cuda_bindings/cuda/bindings/_internal/nvfatbin_windows.pyx
#	cuda_bindings/cuda/bindings/_internal/nvjitlink.pxd
#	cuda_bindings/cuda/bindings/_internal/nvjitlink_linux.pyx
#	cuda_bindings/cuda/bindings/_internal/nvjitlink_windows.pyx
#	cuda_bindings/cuda/bindings/_internal/nvml_linux.pyx
#	cuda_bindings/cuda/bindings/_internal/nvml_windows.pyx
#	cuda_bindings/cuda/bindings/_internal/nvrtc_linux.pyx
#	cuda_bindings/cuda/bindings/_internal/nvrtc_windows.pyx
#	cuda_bindings/cuda/bindings/_internal/nvvm_linux.pyx
#	cuda_bindings/cuda/bindings/_internal/nvvm_windows.pyx
#	cuda_bindings/cuda/bindings/_v2/nvrtc.pxd
#	cuda_bindings/cuda/bindings/_v2/nvrtc.pyx
#	cuda_bindings/cuda/bindings/cudla.pxd
#	cuda_bindings/cuda/bindings/cudla.pyx
#	cuda_bindings/cuda/bindings/cufile.pyx
#	cuda_bindings/cuda/bindings/cycudla.pxd
#	cuda_bindings/cuda/bindings/cycudla.pyx
#	cuda_bindings/cuda/bindings/cydriver.pxd
#	cuda_bindings/cuda/bindings/cynvfatbin.pxd
#	cuda_bindings/cuda/bindings/cynvjitlink.pxd
#	cuda_bindings/cuda/bindings/cynvjitlink.pyx
#	cuda_bindings/cuda/bindings/cynvml.pxd
#	cuda_bindings/cuda/bindings/cynvrtc.pxd
#	cuda_bindings/cuda/bindings/nvfatbin.pxd
#	cuda_bindings/cuda/bindings/nvfatbin.pyx
#	cuda_bindings/cuda/bindings/nvjitlink.pxd
#	cuda_bindings/cuda/bindings/nvjitlink.pyx
#	cuda_bindings/cuda/bindings/nvml.pxd
#	cuda_bindings/cuda/bindings/nvml.pyx
#	cuda_bindings/cuda/bindings/nvrtc.pyx
#	cuda_bindings/cuda/bindings/nvvm.pxd
#	cuda_bindings/cuda/bindings/nvvm.pyx
#	cuda_bindings/docs/source/module/driver.rst
#	cuda_bindings/docs/source/module/nvrtc.rst
#	cuda_bindings/docs/source/module/runtime.rst
#	cuda_bindings/tests/nvml/test_device.py
#	cuda_core/tests/system/test_system_device.py
…2619)

* docs(cuda.core): don't document APIs accept dict for options

* test(cuda.core): use Options dataclasses instead of dicts in MR tests
…NVIDIA#2612)

Signed-off-by: andrewwhitecdw <andrewwhitecdw@users.noreply.github.com>
Co-authored-by: andrewwhitecdw <andrewwhitecdw@users.noreply.github.com>
@rwgk

rwgk commented Aug 15, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test 1ebebc5

@rwgk

rwgk commented Aug 15, 2026

Copy link
Copy Markdown
Contributor Author

I added two follow-up commits based on the failures in CI run 31865723802.

Restore compatibility coverage for clock event reasons (df5356d)

All 11 failing Linux AArch64 test jobs failed at the same enum-coverage case. cuda.core exposes ClocksEventReasons.BOARD_LIMIT and ClocksEventReasons.RELIABILITY, but the older cuda.bindings versions used by the CUDA 12.9 and 13.3 compatibility rows do not yet expose the corresponding NVML enum names.

The production mapping already handles this intentionally: when those two names are absent, it uses their stable numeric NVML values. The generic coverage test had lost the matching compatibility allowance, so it incorrectly required an older binding to contain names that only a newer binding provides.

This commit restores the narrow, dynamic test guard from ctk-next commit 91aa75d:

  • each wrapper member is exempted only when its corresponding binding member is absent;
  • with CUDA 13.4 bindings, both names are present, the exemption set is empty, and the normal full-coverage assertion still applies;
  • no runtime behavior and no other enum coverage is changed.

This is therefore a compatibility-test correction rather than a blanket skip. It lets the intended older-bindings matrix continue checking all members that those bindings can actually provide.

Harden prior-branch artifact lookup (1ebebc5)

Two Linux wheel-build jobs failed after their current CUDA 13.4 builds had succeeded, while assembling the CUDA 12 half of the combined cuda.core wheel. Each matrix job independently asked gh run list for one successful run on 12.9.x and assumed that result was the newest usable run.

That assumption did not hold in this CI run: jobs started within roughly the same minute resolved several different historical run IDs. The Python 3.14t job selected a run whose matching artifact had expired, while the Python 3.15 job selected a run from before that artifact existed. The logs do not establish which GitHub/CLI layer produced the stale ordering, so this change does not depend on attributing the behavior to a specific external bug.

The lookup now:

  • fetches a bounded set of completed branch runs, filters successful runs explicitly, and sorts them by creation time;
  • scans newest to oldest and uses the paginated Actions artifact API to require a matching, unexpired bindings wheel before selecting a run;
  • also requires cuda-python-wheel when a test job will download it, so all requested artifacts must come from the same run;
  • distinguishes the bindings wheel artifact from its -tests sibling, preventing a tests-only match from qualifying a run;
  • preserves branch lookup without artifact requirements, including the nightly run_id + head_sha output, and leaves tag lookup unchanged.

All three prior-branch consumers now use the validated lookup: the wheel builder and the Linux and Windows wheel-test workflows.

The new standalone tests use a fake gh executable to cover unordered and failed runs, a workflow selected by filename rather than display name, fallback past expired/missing artifacts, multiple artifacts required from one run, a live -tests artifact with an expired wheel, and artifact-API failure propagation.

Validation

  • cuda_core/tests/test_enum_coverage.py: 30 passed with --noconftest
  • ci/tools/tests: 60 passed with --noconftest
  • bash -n and standalone shellcheck for ci/tools/lookup-run-id
  • actionlint, YAML, Ruff, SPDX, and git diff --check
  • full pre-commit run --all-files passed with check-pixi-cuda-version intentionally skipped because CUDA 13.4 Conda packages are not available yet

The CI rerun remains the authoritative cross-version check: the local environment has CUDA 13.4 bindings, whereas the previously failing rows exercise the conditional enum guard with CUDA 12.9/13.3 bindings and the real prior-branch artifact inventory.

@rwgk rwgk mentioned this pull request Aug 15, 2026
2 tasks
@rwgk

rwgk commented Aug 15, 2026

Copy link
Copy Markdown
Contributor Author

…ess (NVIDIA#2081)

* chore: declare minimum scope on pr-metadata-check workflow

Signed-off-by: Arpit Jain <arpitjain099@gmail.com>

* chore: remove unused contents permission

---------

Signed-off-by: Arpit Jain <arpitjain099@gmail.com>
Co-authored-by: Ralf W. Grosse-Kunstleve <rgrossekunst@nvidia.com>
@github-actions

Copy link
Copy Markdown

rwgk and others added 18 commits August 17, 2026 07:37
Treat per-domain clock queries as independently optional. Individual domains may reject minimum, maximum, or current clock queries even on newer devices.
…#2639)

* fix(cuda.core): emit -numba-debug with a single dash for NVVM

ProgramOptions(numba_debug=True) always failed on the NVVM backend.
The option was emitted as --numba-debug, but libNVVM's parser accepts
only single-dashed options, so every such compile raised
NVVM_ERROR_INVALID_OPTION. NVRTC tolerates both spellings and was
unaffected. This was the only double-dashed option in the NVVM path,
which otherwise emits -arch=, -g and -ftz=1.

The defect hid itself: test_nvvm_program_numba_debug was gated on a
probe that asked libNVVM about the same wrong spelling, so the test
skipped everywhere and had never executed. Fixing the probe makes it
run, and it passes. Its skip reason also blamed CTK 13.2, which is not
the cause.

libNVVM from CUDA 12.x rejects both spellings, so the option remains
unavailable there; the release note says so.

Closes NVIDIA#2570

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(cuda.core): reject double-dashed NVVM options at the source

Add a guard at the single exit point of _prepare_nvvm_options_impl that
raises if any option is double-dashed. libNVVM accepts only single-dashed
options, and every option on this path is generated from typed fields, so
a double dash can only mean a bug in cuda.core rather than bad user input.
Raising here names the offending option instead of leaving the user with
libNVVM's opaque NVVM_ERROR_INVALID_OPTION.

The guard is a separate cpdef helper so a test can exercise it directly;
an inline check would be unreachable and therefore unverifiable. A second
test sets every NVVM-supported field of ProgramOptions and asserts no
emitted option is double-dashed, so the invariant covers options added
later.

Verified by mutation: restoring --numba-debug turns three tests red, and
the compile test then fails with this guard's error rather than libNVVM's.

The NVRTC path keeps --numba-debug, which it accepts; the guard is scoped
to the NVVM emitter.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Run the Python build driver from the batch wrapper and feed Cython relative source names after switching to the tests/cython directory. This avoids duplicating the absolute checkout path under build/temp and preserves the build result.
Co-authored-by: Michael Wang <isVoid@users.noreply.github.com>
…re (NVIDIA#2524)

* test(cuda.core): verify PDL GraphBuilder capture and overlap

Cover GraphBuilder stream-capture for programmatic_stream_serialization:
functional launch, programmatic dependency edge mapping, and Hopper+
overlap (xfail if opportunistic), plus 1.2.0 release notes.

* docs(cuda.core): use runtime PDL attribute name in 1.2.0 notes

Refer to cudaLaunchAttributeProgrammaticStreamSerialization instead of
the driver-style CU_LAUNCH_ATTRIBUTE_* spelling.

* resolve pre-commit errors

* test(cuda.core): skip PDL overlap graph capture on NumPy < 2.2.5

The test writes host buffers from np.from_dlpack, which are read-only before NumPy 2.2.5 (GH #28632).

* test(cuda.core): use init_cuda in PDL overlap graph capture test

Align with other graph builder tests so context setup and teardown stay consistent.

* test(cuda.core): clarify PDL graph capture doc references

Drop fragile Programming Guide section numbers and note Driver vs Runtime enum name equivalence at the edge asserts.

* test(cuda.core): share PDL overlap protocol via helper runner

Extract kernels and the same-stream / graph-capture overlap check into
run_pdl_overlap_check so launcher and GraphBuilder tests stay in sync.

* test(cuda.core): rename PDL overlap tests to emphasize same-stream

Both direct and graph-capture paths are same-stream; update names and docs accordingly.

* test(cuda.core): tidy PDL overlap helper import order and docstring

* test(cuda.core): drop shared PDL overlap helper for clearer per-path tests

Keep the stream overlap case self-contained in test_launcher, and inline the
graph capture/overlap checks in test_graph_builder so each path stays simple.

* test(cuda.core): rename PDL graph-capture kernels to dummy_kernel

Avoid implying an in-kernel producer/consumer dependency; the test only needs two launches for the programmatic edge assert.

* test(cuda.core): handle versioned graph edge API

* test(cuda.core): skip PDL edge assert on bindings with NVIDIA#1804 UAF

Published cuda-bindings <13.3.0 (or <12.9.7 on 12.x) returns dangling
CUgraphEdgeData from cuGraphGetEdges; also fix release-note RST indent.

---------

Co-authored-by: Michael Wang <isVoid@users.noreply.github.com>
)

cuda.core: introduce copy options for Buffer.copy_to/copy_from

Add an optional `options: CopyOptions` keyword argument to
`Buffer.copy_to` and `Buffer.copy_from`, exposing the same dataclass
introduced by `copy_batch` on the per-buffer path. When set, the copy
is submitted via `cuMemcpyWithAttributesAsync` if both cuda.bindings
and the driver are CUDA 13.2+, the stream isn't `LEGACY_DEFAULT_STREAM`,
and it isn't currently capturing; `PER_THREAD_DEFAULT_STREAM` is
accepted like any other stream. `options=None` is unaffected and
always uses the existing `cuMemcpyAsync` path.

Passing `options` together with `LEGACY_DEFAULT_STREAM` or a capturing
stream raises `TypeError`, matching `copy_batch`; a graph cannot
represent these attributes, so `GraphNode.memcpy` (a plain,
non-attributed copy) is the only way to get a copy into a graph today.

On an older cuda.bindings/driver, `src_access_order` values of
`STREAM` and `ANY` fall back to `cuMemcpyAsync` silently, since
stream-ordered access already satisfies both. `DURING_API_CALL`
promises all source reads complete before the call returns; a
stream-ordered fallback can't honor that, so it raises `RuntimeError`
instead of silently downgrading the guarantee, which could otherwise
let a caller overwrite a source buffer before the real read happens.

While aligning the two APIs, this also fixes two bugs in the existing
`copy_batch`: it previously rejected `PER_THREAD_DEFAULT_STREAM`
outright even though the driver accepts it, and its pre-CUDA-13
fallback loop silently ignored `DURING_API_CALL` despite a stale
comment claiming that case was already rejected. Both now match the
per-buffer behavior via a shared `_reject_unsupported_during_api_call`
helper in `_copy_enums.py`.

`cuMemcpyWithAttributesAsync` is absent from cuda.bindings older than
13.2, so it's routed through a small C++ function-pointer shim
(`_cpp/resource_handles.{cpp,hpp}`) resolved at runtime, avoiding a
hard Cython cimport that would break older-bindings builds.

Tests: new `tests/memory/test_copy_single_options.py` covers data
correctness across all `CopyOptions` fields, the `TypeError`/
`RuntimeError` rejection paths, default-stream-token and graph-capture
behavior (including that `options=None` is unaffected by either), and
`dst=None` auto-allocation. `test_copy_batch.py`/
`test_copy_batch_options.py` gain matching coverage for the
`copy_batch` fixes, plus direct unit tests of the shared
`DURING_API_CALL` guard. `test_memory.py` adds previously-missing
size-mismatch rejection tests for `copy_to`/`copy_from`.

Closes NVIDIA#2365.
* cuda.core: reject register() on a non-IPC memory resource

MP_register read self._ipc_data._alloc_handle._uuid unconditionally.
_ipc_data is None whenever IPC is not enabled, and Cython compiles the
chained access without a none check, so the call terminated the process
with a segmentation fault instead of raising. No exception reached the
caller, so the crash could not be guarded with try.

Check is_ipc_enabled first and raise RuntimeError, matching the wording
the allocation_handle property already uses. The check runs before the
registry insertion, so a rejected registration no longer leaves an entry
behind.

Closes NVIDIA#2568

Signed-off-by: Vyron Vasileiadis <hi@fedonman.com>

* remove trailing whitespace

* test(cuda.core): gate register() IPC guard test on mempool support

test_register_rejects_non_ipc_memory_resource constructed a
DeviceMemoryResource from a bare Device(), which raises
CUDA_ERROR_NOT_SUPPORTED on devices without memory pool support. Every
win-64 TCC job in CI failed there before reaching the assertion under
test.

Take the mempool_device fixture instead, matching how the other
mempool-dependent tests are gated. The fixture skips when
memory_pools_supported is false and already makes the device current,
so the manual Device()/set_current() pair is dropped.

---------

Signed-off-by: Vyron Vasileiadis <hi@fedonman.com>
…th (NVIDIA#2610)

When _capture_tail_node fails, the anonymous-commit cleanup calls
HANDLE_RETURN inside the except handler. If that HANDLE_RETURN also
raises, Python's implicit chaining would emit a confusing "During
handling of the above exception, another exception occurred" message
that buries the real CUDA error. Make the causal relationship explicit
with `raise commit_exc from orig_exc`.

Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Skip artifact discovery and aggregate status outside NVIDIA, matching the existing public-only guards on the nightly test jobs.
…IA#2596)

* test(cuda.core): add note about using multiple conftest modules

* tests refactoring

* include references to pytest docs
… paths (NVIDIA#2658)

`LinkerOptions` carries a public `numba_debug` field that no linking
backend reads. nvJitLink rejects the option under every spelling and the
driver's cuLink API has no corresponding `CUjit_option`, so setting it
does nothing and reports nothing.

It is not merely dead: `_translate_program_options` forwarded
`numba_debug` from `ProgramOptions` into `LinkerOptions` on the
`code_type="ptx"` path, so `Program(ptx, "ptx",
ProgramOptions(numba_debug=True))` silently discarded an option the user
explicitly set.

Make the drop audible without breaking any caller:

- `LinkerOptions.numba_debug` is deprecated. Setting it emits a
  `DeprecationWarning` from `__post_init__` and the value is still
  ignored. The field stays, so no constructor signature changes.
- `_translate_program_options` no longer forwards it and emits a
  `UserWarning` saying it is ignored for `code_type="ptx"`. `UserWarning`
  rather than `DeprecationWarning` because `ProgramOptions.numba_debug`
  is not deprecated -- it is fully supported on NVVM and NVRTC and
  merely inapplicable to a linking backend.
- The option builders are untouched; the linker needs no knowledge of
  `numba_debug` to ignore it.
- `_LinkerBackend.validate` rejects nothing, and `numba_debug` stays out
  of `_LINKER_FIELD_GATES`: it cannot change PTX-path output, so it must
  not perturb the program-cache key.

The warning gates differ on purpose. The linker field uses `is not None`
-- the field itself is going away, so any explicit value earns the
notice, including `False`. The PTX path uses truthiness, matching
`_prepare_nvvm_options_impl`, because `False` asks for nothing.

Removal of `LinkerOptions.numba_debug` is deferred to 2.0.0: the support
policy confines breaking API changes to major-version boundaries and
requires a deprecation notice at least one minor release ahead. Nothing
in the repo tracks a scheduled removal -- the existing precedent
(`Device.max_links`) only says "a future release" -- so a version-gated
test fails the build once the version crosses 2.0.

The NVVM and NVRTC paths are unchanged and still emit the option.

Closes NVIDIA#2640

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sort completed branch runs explicitly and choose the newest successful run whose required artifacts are still available. Validate bindings and metapackage artifacts at all prior-branch download sites, and cover fallback and compatibility behavior with standalone tests.
* Upgrade stubgen-pyx to 0.2.19

* ci: show diff on pre-commit failure to diagnose Windows stubgen mismatch

Temporary diagnostic to see what content actually differs when the
stubgen-pyx-cuda-core hook reports modified files on Windows CI.

* Fix Windows encoding issue
# Conflicts:
#	ci/tools/lookup-run-id
#	ci/tools/tests/test_lookup_run_id.py
#	cuda_core/cuda/core/_device.pyi
#	cuda_core/cuda/core/system/_device.pyi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CI/CD CI/CD infrastructure cuda.bindings Everything related to the cuda.bindings module cuda.core Everything related to the cuda.core module cuda.pathfinder Everything related to the cuda.pathfinder module enhancement Any code-related improvements P0 High priority - Must do!

Projects

None yet

Development

Successfully merging this pull request may close these issues.