From c0e31666461b96329a2ceb430772d156ac0ceb74 Mon Sep 17 00:00:00 2001 From: Martin Durant Date: Mon, 2 Nov 2026 14:04:05 -0500 Subject: [PATCH 1/5] Expose graph/node IDs as ints --- cuda_core/cuda/core/_module.pyi | 7 +++++ cuda_core/cuda/core/_module.pyx | 14 +++++++++ cuda_core/cuda/core/graph/_graph_builder.pyi | 6 ++++ cuda_core/cuda/core/graph/_graph_builder.pyx | 15 ++++++++++ .../cuda/core/graph/_graph_definition.pyi | 6 ++++ .../cuda/core/graph/_graph_definition.pyx | 15 ++++++++++ cuda_core/cuda/core/graph/_graph_node.pyi | 8 +++++ cuda_core/cuda/core/graph/_graph_node.pyx | 29 +++++++++++++++++++ cuda_core/docs/source/api.rst | 9 ++++++ cuda_core/docs/source/release/1.3.0-notes.rst | 6 ++++ .../tests/graph/test_graph_definition.py | 24 +++++++++++++++ 11 files changed, 139 insertions(+) diff --git a/cuda_core/cuda/core/_module.pyi b/cuda_core/cuda/core/_module.pyi index 1212bc1f536..4b41838877e 100644 --- a/cuda_core/cuda/core/_module.pyi +++ b/cuda_core/cuda/core/_module.pyi @@ -97,6 +97,13 @@ class KernelAttributes: @property def cluster_scheduling_policy_preference(self) -> int: """int : The block scheduling policy of a function.""" + @property + def device_node_update_supported(self) -> bool: + """bool : Whether this kernel supports device-side graph node updates. + + Requires the CUDA 13 build and CUDA driver 13.3 or newer. + This attribute is read-only. + """ class KernelOccupancy: """This class offers methods to query occupancy metrics that help determine optimal diff --git a/cuda_core/cuda/core/_module.pyx b/cuda_core/cuda/core/_module.pyx index d4de653406f..d2f69021008 100644 --- a/cuda_core/cuda/core/_module.pyx +++ b/cuda_core/cuda/core/_module.pyx @@ -235,6 +235,20 @@ cdef class KernelAttributes: cydriver.CU_FUNC_ATTRIBUTE_CLUSTER_SCHEDULING_POLICY_PREFERENCE, ) + @property + def device_node_update_supported(self) -> bool: + """bool : Whether this kernel supports device-side graph node updates. + + Requires the CUDA 13 build and CUDA driver 13.3 or newer. + This attribute is read-only. + """ + if cy_driver_version() < (13, 3, 0): + raise NotImplementedError("Device node update queries require CUDA driver 13.3 or newer") + return bool(self._get_cached_attribute( + self._effective_device_id(), + cydriver.CU_FUNC_ATTRIBUTE_DEVICE_NODE_UPDATE_SUPPORTED, + )) + MaxPotentialBlockSizeOccupancyResult = namedtuple( "MaxPotentialBlockSizeOccupancyResult", ("min_grid_size", "max_block_size") diff --git a/cuda_core/cuda/core/graph/_graph_builder.pyi b/cuda_core/cuda/core/graph/_graph_builder.pyi index bf20e0cb3bf..4d159ec269d 100644 --- a/cuda_core/cuda/core/graph/_graph_builder.pyi +++ b/cuda_core/cuda/core/graph/_graph_builder.pyi @@ -469,6 +469,12 @@ class Graph: def is_closed(self) -> bool: """Whether this executable graph has been closed.""" @property + def id(self) -> int: + """The driver-assigned executable graph ID, as used in GraphViz DOT output. + + Requires the CUDA 13 build and CUDA driver 13.1 or newer. + """ + @property def handle(self) -> driver.CUgraphExec: """Return the underlying ``CUgraphExec`` object. diff --git a/cuda_core/cuda/core/graph/_graph_builder.pyx b/cuda_core/cuda/core/graph/_graph_builder.pyx index ce45b4d272c..91530068691 100644 --- a/cuda_core/cuda/core/graph/_graph_builder.pyx +++ b/cuda_core/cuda/core/graph/_graph_builder.pyx @@ -1252,6 +1252,21 @@ cdef class Graph: """Whether this executable graph has been closed.""" return self._h_graph_exec.get() == NULL + @property + def id(self) -> int: + """The driver-assigned executable graph ID, as used in GraphViz DOT output. + + Requires the CUDA 13 build and CUDA driver 13.1 or newer. + """ + if self.is_closed: + raise RuntimeError("Graph is closed") + cdef unsigned int graph_id + if cy_driver_version() < (13, 1, 0): + raise NotImplementedError("Graph IDs require CUDA driver 13.1 or newer") + with nogil: + HANDLE_RETURN(cydriver.cuGraphExecGetId(as_cu(self._h_graph_exec), &graph_id)) + return graph_id + @property def handle(self) -> driver.CUgraphExec: """Return the underlying ``CUgraphExec`` object. diff --git a/cuda_core/cuda/core/graph/_graph_definition.pyi b/cuda_core/cuda/core/graph/_graph_definition.pyi index 6a139eb7935..44676eb2b74 100644 --- a/cuda_core/cuda/core/graph/_graph_definition.pyi +++ b/cuda_core/cuda/core/graph/_graph_definition.pyi @@ -61,6 +61,12 @@ class GraphDefinition: def __eq__(self, other: object) -> bool: ... def __hash__(self) -> int: ... @property + def id(self) -> int: + """The driver-assigned graph ID, as used in GraphViz DOT output. + + Requires the CUDA 13 build and CUDA driver 13.1 or newer. + """ + @property def is_valid(self) -> bool: """Whether this graph definition remains valid.""" @property diff --git a/cuda_core/cuda/core/graph/_graph_definition.pyx b/cuda_core/cuda/core/graph/_graph_definition.pyx index f9254e8c229..4f7472815d8 100644 --- a/cuda_core/cuda/core/graph/_graph_definition.pyx +++ b/cuda_core/cuda/core/graph/_graph_definition.pyx @@ -23,6 +23,7 @@ from cuda.core._rt cimport ( create_graph_node_handle, ) from cuda.core._utils.cuda_utils cimport HANDLE_RETURN +from cuda.core._utils.version cimport cy_driver_version from typing import TYPE_CHECKING @@ -142,6 +143,20 @@ cdef class GraphDefinition: def __hash__(self) -> int: return hash(self._h_graph.get()) + @property + def id(self) -> int: + """The driver-assigned graph ID, as used in GraphViz DOT output. + + Requires the CUDA 13 build and CUDA driver 13.1 or newer. + """ + GD_check_valid(self) + cdef unsigned int graph_id + if cy_driver_version() < (13, 1, 0): + raise NotImplementedError("Graph IDs require CUDA driver 13.1 or newer") + with nogil: + HANDLE_RETURN(cydriver.cuGraphGetId(as_cu(self._h_graph), &graph_id)) + return graph_id + @property def is_valid(self) -> bool: """Whether this graph definition remains valid.""" diff --git a/cuda_core/cuda/core/graph/_graph_node.pyi b/cuda_core/cuda/core/graph/_graph_node.pyi index b22f3d64dcd..e6f41be608a 100644 --- a/cuda_core/cuda/core/graph/_graph_node.pyi +++ b/cuda_core/cuda/core/graph/_graph_node.pyi @@ -42,6 +42,14 @@ class GraphNode: The node type enum value, or None for the entry node. """ @property + def local_id(self) -> int: + """The node's ID within its graph, as used in GraphViz DOT output. + """ + @property + def tools_id(self) -> int: + """The node's ID reported by CUDA profiling and tooling interfaces. + """ + @property def graph(self) -> GraphDefinition: """Return the GraphDefinition this node belongs to.""" @property diff --git a/cuda_core/cuda/core/graph/_graph_node.pyx b/cuda_core/cuda/core/graph/_graph_node.pyx index 4c81860d39a..f49a9435ada 100644 --- a/cuda_core/cuda/core/graph/_graph_node.pyx +++ b/cuda_core/cuda/core/graph/_graph_node.pyx @@ -65,6 +65,7 @@ from cuda.core._rt cimport ( make_opaque_py, ) from cuda.core._utils.cuda_utils cimport HANDLE_RETURN, _parse_fill_value +from cuda.core._utils.version cimport cy_driver_version from cuda.core.graph._host_callback cimport ( _resolve_host_callback, @@ -142,6 +143,34 @@ cdef class GraphNode: HANDLE_RETURN(cydriver.cuGraphNodeGetType(node, &node_type)) return driver.CUgraphNodeType(node_type) + @property + def local_id(self) -> int: + """The node's ID within its graph, as used in GraphViz DOT output. + """ + GN_check_valid(self) + if self._is_entry: + raise ValueError("The entry node has no driver-assigned ID") + cdef unsigned int node_id + if cy_driver_version() < (13, 1, 0): + raise NotImplementedError("Graph node IDs require CUDA driver 13.1 or newer") + with nogil: + HANDLE_RETURN(cydriver.cuGraphNodeGetLocalId(as_cu(self._h_node), &node_id)) + return node_id + + @property + def tools_id(self) -> int: + """The node's ID reported by CUDA profiling and tooling interfaces. + """ + GN_check_valid(self) + if self._is_entry: + raise ValueError("The entry node has no driver-assigned ID") + cdef unsigned long long node_id + if cy_driver_version() < (13, 1, 0): + raise NotImplementedError("Graph node IDs require CUDA driver 13.1 or newer") + with nogil: + HANDLE_RETURN(cydriver.cuGraphNodeGetToolsId(as_cu(self._h_node), &node_id)) + return node_id + @property def graph(self) -> GraphDefinition: """Return the GraphDefinition this node belongs to.""" diff --git a/cuda_core/docs/source/api.rst b/cuda_core/docs/source/api.rst index d9c4acf206c..5644bdb6701 100644 --- a/cuda_core/docs/source/api.rst +++ b/cuda_core/docs/source/api.rst @@ -137,6 +137,15 @@ CPU overhead. Graphs can be constructed in two ways: edges. Both produce an executable :class:`~graph.Graph` that can be launched on a :class:`Stream`. +With CUDA >= 13.1, graph definitions and +executable graphs expose a read-only integer, ``id``. Nodes expose ``local_id`` +(unique within their graph) and ``tools_id`` (for profiler correlation). +Use ``node.graph`` to obtain the containing graph definition; this view +shares ownership of the underlying graph. IDs are ephemeral, driver-assigned. + +``kernel.attributes.device_node_update_supported`` reports whether a kernel +supports device-side node updates. It requires CUDA >= 13.3. + .. currentmodule:: cuda.core .. autosummary:: diff --git a/cuda_core/docs/source/release/1.3.0-notes.rst b/cuda_core/docs/source/release/1.3.0-notes.rst index 5d6521d30a8..3a90454e655 100644 --- a/cuda_core/docs/source/release/1.3.0-notes.rst +++ b/cuda_core/docs/source/release/1.3.0-notes.rst @@ -45,6 +45,12 @@ Breaking Changes New features ------------ +- Added read-only ``GraphDefinition.id``, ``Graph.id``, ``GraphNode.local_id`` + and ``GraphNode.tools_id`` properties (CUDA 13.1+), and + ``KernelAttributes.device_node_update_supported`` (CUDA 13.3+). + The existing ``GraphNode.graph`` property provides containing-graph navigation. + (`#2360 `__) + - Added incremental linking to :class:`Linker` through ``LinkerOptions(incremental=True)`` on nvJitLink 13.2 or newer. A partial native result is returned as a CUBIN and can be passed directly to another diff --git a/cuda_core/tests/graph/test_graph_definition.py b/cuda_core/tests/graph/test_graph_definition.py index 16d44fb6034..2bca354539b 100644 --- a/cuda_core/tests/graph/test_graph_definition.py +++ b/cuda_core/tests/graph/test_graph_definition.py @@ -821,6 +821,30 @@ def test_graphdef_handle_valid(init_cuda): assert int(sample_graphdef.handle) != 0 +def test_graph_identity_attributes(init_cuda): + from cuda.core._utils.version import driver_version + + definition = GraphDefinition() + node = definition.empty() + other = definition.empty() + graph = definition.instantiate() + + try: + if driver_version() < (13, 1, 0): + with pytest.raises(NotImplementedError): + _ = definition.id + with pytest.raises(NotImplementedError): + _ = graph.id + return + assert isinstance(definition.id, int) + assert isinstance(graph.id, int) + assert node.graph == definition + assert node.local_id != other.local_id + assert node.tools_id != other.tools_id + finally: + graph.close() + + def test_graphdef_entry_is_virtual(init_cuda): """Internal entry node is virtual (no pred/succ, type is None).""" sample_graphdef = GraphDefinition() From ec60763a41c0b8c06e6f621ffb0e03fe19460527 Mon Sep 17 00:00:00 2001 From: Martin Durant Date: Mon, 2 Nov 2026 14:13:12 -0500 Subject: [PATCH 2/5] Shorted docstrings --- cuda_core/cuda/core/graph/_graph_builder.pyi | 2 +- cuda_core/cuda/core/graph/_graph_builder.pyx | 2 +- cuda_core/cuda/core/graph/_graph_node.pyi | 2 +- cuda_core/cuda/core/graph/_graph_node.pyx | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cuda_core/cuda/core/graph/_graph_builder.pyi b/cuda_core/cuda/core/graph/_graph_builder.pyi index 4d159ec269d..dff312b831c 100644 --- a/cuda_core/cuda/core/graph/_graph_builder.pyi +++ b/cuda_core/cuda/core/graph/_graph_builder.pyi @@ -472,7 +472,7 @@ class Graph: def id(self) -> int: """The driver-assigned executable graph ID, as used in GraphViz DOT output. - Requires the CUDA 13 build and CUDA driver 13.1 or newer. + Requires CUDA >= 13.1. """ @property def handle(self) -> driver.CUgraphExec: diff --git a/cuda_core/cuda/core/graph/_graph_builder.pyx b/cuda_core/cuda/core/graph/_graph_builder.pyx index 91530068691..27bc9336f42 100644 --- a/cuda_core/cuda/core/graph/_graph_builder.pyx +++ b/cuda_core/cuda/core/graph/_graph_builder.pyx @@ -1256,7 +1256,7 @@ cdef class Graph: def id(self) -> int: """The driver-assigned executable graph ID, as used in GraphViz DOT output. - Requires the CUDA 13 build and CUDA driver 13.1 or newer. + Requires CUDA >= 13.1. """ if self.is_closed: raise RuntimeError("Graph is closed") diff --git a/cuda_core/cuda/core/graph/_graph_node.pyi b/cuda_core/cuda/core/graph/_graph_node.pyi index e6f41be608a..4d5f76c070f 100644 --- a/cuda_core/cuda/core/graph/_graph_node.pyi +++ b/cuda_core/cuda/core/graph/_graph_node.pyi @@ -43,7 +43,7 @@ class GraphNode: """ @property def local_id(self) -> int: - """The node's ID within its graph, as used in GraphViz DOT output. + """The node's ID within its graph. """ @property def tools_id(self) -> int: diff --git a/cuda_core/cuda/core/graph/_graph_node.pyx b/cuda_core/cuda/core/graph/_graph_node.pyx index f49a9435ada..174a9df9183 100644 --- a/cuda_core/cuda/core/graph/_graph_node.pyx +++ b/cuda_core/cuda/core/graph/_graph_node.pyx @@ -145,7 +145,7 @@ cdef class GraphNode: @property def local_id(self) -> int: - """The node's ID within its graph, as used in GraphViz DOT output. + """The node's ID within its graph. """ GN_check_valid(self) if self._is_entry: From d17f369c5d75fd6cdf0091198526b7043a2067ab Mon Sep 17 00:00:00 2001 From: Martin Durant Date: Mon, 2 Nov 2026 16:44:07 -0500 Subject: [PATCH 3/5] Add cuda 12 compile-time guards --- cuda_core/cuda/core/_module.pyx | 15 +++++---- cuda_core/cuda/core/graph/_graph_builder.pyx | 15 +++++---- .../cuda/core/graph/_graph_definition.pyx | 18 ++++++---- cuda_core/cuda/core/graph/_graph_node.pyx | 33 +++++++++++-------- cuda_core/docs/source/release/1.3.0-notes.rst | 7 ++++ 5 files changed, 56 insertions(+), 32 deletions(-) diff --git a/cuda_core/cuda/core/_module.pyx b/cuda_core/cuda/core/_module.pyx index d2f69021008..2a586ec947d 100644 --- a/cuda_core/cuda/core/_module.pyx +++ b/cuda_core/cuda/core/_module.pyx @@ -242,12 +242,15 @@ cdef class KernelAttributes: Requires the CUDA 13 build and CUDA driver 13.3 or newer. This attribute is read-only. """ - if cy_driver_version() < (13, 3, 0): - raise NotImplementedError("Device node update queries require CUDA driver 13.3 or newer") - return bool(self._get_cached_attribute( - self._effective_device_id(), - cydriver.CU_FUNC_ATTRIBUTE_DEVICE_NODE_UPDATE_SUPPORTED, - )) + IF CUDA_CORE_BUILD_MAJOR >= 13: + if cy_driver_version() < (13, 3, 0): + raise NotImplementedError("Device node update queries require CUDA driver 13.3 or newer") + return bool(self._get_cached_attribute( + self._effective_device_id(), + cydriver.CU_FUNC_ATTRIBUTE_DEVICE_NODE_UPDATE_SUPPORTED, + )) + ELSE: + raise NotImplementedError("Device node update queries require the CUDA 13 build of cuda.core") MaxPotentialBlockSizeOccupancyResult = namedtuple( diff --git a/cuda_core/cuda/core/graph/_graph_builder.pyx b/cuda_core/cuda/core/graph/_graph_builder.pyx index 41db219a808..9a62e6184a4 100644 --- a/cuda_core/cuda/core/graph/_graph_builder.pyx +++ b/cuda_core/cuda/core/graph/_graph_builder.pyx @@ -1260,12 +1260,15 @@ cdef class Graph: """ if self.is_closed: raise RuntimeError("Graph is closed") - cdef unsigned int graph_id - if cy_driver_version() < (13, 1, 0): - raise NotImplementedError("Graph IDs require CUDA driver 13.1 or newer") - with nogil: - HANDLE_RETURN(cydriver.cuGraphExecGetId(as_cu(self._h_graph_exec), &graph_id)) - return graph_id + IF CUDA_CORE_BUILD_MAJOR >= 13: + cdef unsigned int graph_id + if cy_driver_version() < (13, 1, 0): + raise NotImplementedError("Graph IDs require CUDA driver 13.1 or newer") + with nogil: + HANDLE_RETURN(cydriver.cuGraphExecGetId(as_cu(self._h_graph_exec), &graph_id)) + return graph_id + ELSE: + raise NotImplementedError("Graph IDs require the CUDA 13 build of cuda.core") @property def handle(self) -> driver.CUgraphExec: diff --git a/cuda_core/cuda/core/graph/_graph_definition.pyx b/cuda_core/cuda/core/graph/_graph_definition.pyx index 4f7472815d8..4e0c7c12a80 100644 --- a/cuda_core/cuda/core/graph/_graph_definition.pyx +++ b/cuda_core/cuda/core/graph/_graph_definition.pyx @@ -23,7 +23,8 @@ from cuda.core._rt cimport ( create_graph_node_handle, ) from cuda.core._utils.cuda_utils cimport HANDLE_RETURN -from cuda.core._utils.version cimport cy_driver_version +IF CUDA_CORE_BUILD_MAJOR >= 13: + from cuda.core._utils.version cimport cy_driver_version from typing import TYPE_CHECKING @@ -150,12 +151,15 @@ cdef class GraphDefinition: Requires the CUDA 13 build and CUDA driver 13.1 or newer. """ GD_check_valid(self) - cdef unsigned int graph_id - if cy_driver_version() < (13, 1, 0): - raise NotImplementedError("Graph IDs require CUDA driver 13.1 or newer") - with nogil: - HANDLE_RETURN(cydriver.cuGraphGetId(as_cu(self._h_graph), &graph_id)) - return graph_id + IF CUDA_CORE_BUILD_MAJOR >= 13: + cdef unsigned int graph_id + if cy_driver_version() < (13, 1, 0): + raise NotImplementedError("Graph IDs require CUDA driver 13.1 or newer") + with nogil: + HANDLE_RETURN(cydriver.cuGraphGetId(as_cu(self._h_graph), &graph_id)) + return graph_id + ELSE: + raise NotImplementedError("Graph IDs require the CUDA 13 build of cuda.core") @property def is_valid(self) -> bool: diff --git a/cuda_core/cuda/core/graph/_graph_node.pyx b/cuda_core/cuda/core/graph/_graph_node.pyx index 83ab9b5ce59..82c30692466 100644 --- a/cuda_core/cuda/core/graph/_graph_node.pyx +++ b/cuda_core/cuda/core/graph/_graph_node.pyx @@ -65,7 +65,8 @@ from cuda.core._rt cimport ( make_opaque_py, ) from cuda.core._utils.cuda_utils cimport HANDLE_RETURN, _parse_fill_value -from cuda.core._utils.version cimport cy_driver_version +IF CUDA_CORE_BUILD_MAJOR >= 13: + from cuda.core._utils.version cimport cy_driver_version from cuda.core._host_callback cimport ( _resolve_host_callback, @@ -150,12 +151,15 @@ cdef class GraphNode: GN_check_valid(self) if self._is_entry: raise ValueError("The entry node has no driver-assigned ID") - cdef unsigned int node_id - if cy_driver_version() < (13, 1, 0): - raise NotImplementedError("Graph node IDs require CUDA driver 13.1 or newer") - with nogil: - HANDLE_RETURN(cydriver.cuGraphNodeGetLocalId(as_cu(self._h_node), &node_id)) - return node_id + IF CUDA_CORE_BUILD_MAJOR >= 13: + cdef unsigned int node_id + if cy_driver_version() < (13, 1, 0): + raise NotImplementedError("Graph node IDs require CUDA driver 13.1 or newer") + with nogil: + HANDLE_RETURN(cydriver.cuGraphNodeGetLocalId(as_cu(self._h_node), &node_id)) + return node_id + ELSE: + raise NotImplementedError("Graph node IDs require the CUDA 13 build of cuda.core") @property def tools_id(self) -> int: @@ -164,12 +168,15 @@ cdef class GraphNode: GN_check_valid(self) if self._is_entry: raise ValueError("The entry node has no driver-assigned ID") - cdef unsigned long long node_id - if cy_driver_version() < (13, 1, 0): - raise NotImplementedError("Graph node IDs require CUDA driver 13.1 or newer") - with nogil: - HANDLE_RETURN(cydriver.cuGraphNodeGetToolsId(as_cu(self._h_node), &node_id)) - return node_id + IF CUDA_CORE_BUILD_MAJOR >= 13: + cdef unsigned long long node_id + if cy_driver_version() < (13, 1, 0): + raise NotImplementedError("Graph node IDs require CUDA driver 13.1 or newer") + with nogil: + HANDLE_RETURN(cydriver.cuGraphNodeGetToolsId(as_cu(self._h_node), &node_id)) + return node_id + ELSE: + raise NotImplementedError("Graph node IDs require the CUDA 13 build of cuda.core") @property def graph(self) -> GraphDefinition: diff --git a/cuda_core/docs/source/release/1.3.0-notes.rst b/cuda_core/docs/source/release/1.3.0-notes.rst index 3b2988e7e9b..194b713c148 100644 --- a/cuda_core/docs/source/release/1.3.0-notes.rst +++ b/cuda_core/docs/source/release/1.3.0-notes.rst @@ -118,6 +118,13 @@ New features Fixes and enhancements ---------------------- +- ``register()`` on a :class:`~_memory.DeviceMemoryResource` or a + :class:`PinnedMemoryResource` now raises ``ValueError`` when the resource + already has a different UUID. The check used to be an ``assert``, so under + ``python -O`` a mismatched UUID silently rewrote the resource's UUID and + corrupted the IPC registry. + (`#2697 `__) + - A :class:`~_memory.DeviceMemoryResource` or a :class:`VirtualMemoryResource` sent through ``multiprocessing`` now names its device, and the ``VirtualMemoryResource`` ``peers``, by UUID. The receiving process maps From 84f8dc82ed7cced4ecb8d281428a1969d7ecb044 Mon Sep 17 00:00:00 2001 From: Martin Durant Date: Tue, 3 Nov 2026 09:45:54 -0500 Subject: [PATCH 4/5] Make messages match --- cuda_core/cuda/core/_module.pyx | 2 +- cuda_core/cuda/core/graph/_graph_builder.pyx | 2 +- cuda_core/cuda/core/graph/_graph_definition.pyx | 2 +- cuda_core/cuda/core/graph/_graph_node.pyx | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cuda_core/cuda/core/_module.pyx b/cuda_core/cuda/core/_module.pyx index 2a586ec947d..9b683d43c3e 100644 --- a/cuda_core/cuda/core/_module.pyx +++ b/cuda_core/cuda/core/_module.pyx @@ -250,7 +250,7 @@ cdef class KernelAttributes: cydriver.CU_FUNC_ATTRIBUTE_DEVICE_NODE_UPDATE_SUPPORTED, )) ELSE: - raise NotImplementedError("Device node update queries require the CUDA 13 build of cuda.core") + raise NotImplementedError("Device node update queries require CUDA driver 13.3 or newer") MaxPotentialBlockSizeOccupancyResult = namedtuple( diff --git a/cuda_core/cuda/core/graph/_graph_builder.pyx b/cuda_core/cuda/core/graph/_graph_builder.pyx index 9a62e6184a4..c439f9a255d 100644 --- a/cuda_core/cuda/core/graph/_graph_builder.pyx +++ b/cuda_core/cuda/core/graph/_graph_builder.pyx @@ -1268,7 +1268,7 @@ cdef class Graph: HANDLE_RETURN(cydriver.cuGraphExecGetId(as_cu(self._h_graph_exec), &graph_id)) return graph_id ELSE: - raise NotImplementedError("Graph IDs require the CUDA 13 build of cuda.core") + raise NotImplementedError("Graph IDs require CUDA driver 13.1 or newer") @property def handle(self) -> driver.CUgraphExec: diff --git a/cuda_core/cuda/core/graph/_graph_definition.pyx b/cuda_core/cuda/core/graph/_graph_definition.pyx index 4e0c7c12a80..c785a586046 100644 --- a/cuda_core/cuda/core/graph/_graph_definition.pyx +++ b/cuda_core/cuda/core/graph/_graph_definition.pyx @@ -159,7 +159,7 @@ cdef class GraphDefinition: HANDLE_RETURN(cydriver.cuGraphGetId(as_cu(self._h_graph), &graph_id)) return graph_id ELSE: - raise NotImplementedError("Graph IDs require the CUDA 13 build of cuda.core") + raise NotImplementedError("Graph IDs require CUDA driver 13.1 or newer") @property def is_valid(self) -> bool: diff --git a/cuda_core/cuda/core/graph/_graph_node.pyx b/cuda_core/cuda/core/graph/_graph_node.pyx index 82c30692466..4a0f96b2be5 100644 --- a/cuda_core/cuda/core/graph/_graph_node.pyx +++ b/cuda_core/cuda/core/graph/_graph_node.pyx @@ -159,7 +159,7 @@ cdef class GraphNode: HANDLE_RETURN(cydriver.cuGraphNodeGetLocalId(as_cu(self._h_node), &node_id)) return node_id ELSE: - raise NotImplementedError("Graph node IDs require the CUDA 13 build of cuda.core") + raise NotImplementedError("Graph node IDs require CUDA driver 13.1 or newer") @property def tools_id(self) -> int: @@ -176,7 +176,7 @@ cdef class GraphNode: HANDLE_RETURN(cydriver.cuGraphNodeGetToolsId(as_cu(self._h_node), &node_id)) return node_id ELSE: - raise NotImplementedError("Graph node IDs require the CUDA 13 build of cuda.core") + raise NotImplementedError("Graph node IDs require CUDA driver 13.1 or newer") @property def graph(self) -> GraphDefinition: From 45c9a181872b26b04acb562d1668ae566ae6c1ac Mon Sep 17 00:00:00 2001 From: Martin Durant Date: Wed, 4 Nov 2026 14:43:39 -0500 Subject: [PATCH 5/5] Small changes --- cuda_core/cuda/core/_module.pyi | 4 ++-- cuda_core/cuda/core/_module.pyx | 4 ++-- cuda_core/cuda/core/graph/_graph_definition.pyi | 2 +- cuda_core/cuda/core/graph/_graph_definition.pyx | 2 +- cuda_core/cuda/core/graph/_graph_node.pyi | 4 ++++ cuda_core/cuda/core/graph/_graph_node.pyx | 12 ++++++++---- cuda_core/docs/source/release/1.3.0-notes.rst | 4 ++-- cuda_core/tests/graph/test_graph_definition.py | 8 ++++++-- cuda_core/tests/test_module.py | 13 +++++++++++++ 9 files changed, 39 insertions(+), 14 deletions(-) diff --git a/cuda_core/cuda/core/_module.pyi b/cuda_core/cuda/core/_module.pyi index 4b41838877e..3cf52899a1d 100644 --- a/cuda_core/cuda/core/_module.pyi +++ b/cuda_core/cuda/core/_module.pyi @@ -99,9 +99,9 @@ class KernelAttributes: """int : The block scheduling policy of a function.""" @property def device_node_update_supported(self) -> bool: - """bool : Whether this kernel supports device-side graph node updates. + """bool : Whether this kernel can be the target of device-side graph node updates. - Requires the CUDA 13 build and CUDA driver 13.3 or newer. + Requires CUDA 13 build and CUDA driver 13.3+. This attribute is read-only. """ diff --git a/cuda_core/cuda/core/_module.pyx b/cuda_core/cuda/core/_module.pyx index 0989a106626..dab050faaab 100644 --- a/cuda_core/cuda/core/_module.pyx +++ b/cuda_core/cuda/core/_module.pyx @@ -237,9 +237,9 @@ cdef class KernelAttributes: @property def device_node_update_supported(self) -> bool: - """bool : Whether this kernel supports device-side graph node updates. + """bool : Whether this kernel can be the target of device-side graph node updates. - Requires the CUDA 13 build and CUDA driver 13.3 or newer. + Requires CUDA 13 build and CUDA driver 13.3+. This attribute is read-only. """ IF CUDA_CORE_BUILD_MAJOR >= 13: diff --git a/cuda_core/cuda/core/graph/_graph_definition.pyi b/cuda_core/cuda/core/graph/_graph_definition.pyi index f62705c0c3c..9af0b154826 100644 --- a/cuda_core/cuda/core/graph/_graph_definition.pyi +++ b/cuda_core/cuda/core/graph/_graph_definition.pyi @@ -67,7 +67,7 @@ class GraphDefinition: def id(self) -> int: """The driver-assigned graph ID, as used in GraphViz DOT output. - Requires the CUDA 13 build and CUDA driver 13.1 or newer. + Requires CUDA 13 build and driver 13.1+ """ @property def is_valid(self) -> bool: diff --git a/cuda_core/cuda/core/graph/_graph_definition.pyx b/cuda_core/cuda/core/graph/_graph_definition.pyx index 6b165e6f5ea..079fb9804a5 100644 --- a/cuda_core/cuda/core/graph/_graph_definition.pyx +++ b/cuda_core/cuda/core/graph/_graph_definition.pyx @@ -151,7 +151,7 @@ cdef class GraphDefinition: def id(self) -> int: """The driver-assigned graph ID, as used in GraphViz DOT output. - Requires the CUDA 13 build and CUDA driver 13.1 or newer. + Requires CUDA 13 build and driver 13.1+ """ GD_check_valid(self) IF CUDA_CORE_BUILD_MAJOR >= 13: diff --git a/cuda_core/cuda/core/graph/_graph_node.pyi b/cuda_core/cuda/core/graph/_graph_node.pyi index 3d20cd96385..45498c550b3 100644 --- a/cuda_core/cuda/core/graph/_graph_node.pyi +++ b/cuda_core/cuda/core/graph/_graph_node.pyi @@ -45,10 +45,14 @@ class GraphNode: @property def local_id(self) -> int: """The node's ID within its graph. + + Requires CUDA 13 build and driver 13.1+ """ @property def tools_id(self) -> int: """The node's ID reported by CUDA profiling and tooling interfaces. + + Requires CUDA 13 build and driver 13.1+ """ @property def graph(self) -> GraphDefinition: diff --git a/cuda_core/cuda/core/graph/_graph_node.pyx b/cuda_core/cuda/core/graph/_graph_node.pyx index 8db538b8213..c5bdc1da92b 100644 --- a/cuda_core/cuda/core/graph/_graph_node.pyx +++ b/cuda_core/cuda/core/graph/_graph_node.pyx @@ -150,6 +150,8 @@ cdef class GraphNode: @property def local_id(self) -> int: """The node's ID within its graph. + + Requires CUDA 13 build and driver 13.1+ """ GN_check_valid(self) if self._is_entry: @@ -157,16 +159,18 @@ cdef class GraphNode: IF CUDA_CORE_BUILD_MAJOR >= 13: cdef unsigned int node_id if cy_driver_version() < (13, 1, 0): - raise NotImplementedError("Graph node IDs require CUDA driver 13.1 or newer") + raise NotImplementedError("Graph IDs require a CUDA 13 build of cuda.core and CUDA driver 13.1 or newer") with nogil: HANDLE_RETURN(cydriver.cuGraphNodeGetLocalId(as_cu(self._h_node), &node_id)) return node_id ELSE: - raise NotImplementedError("Graph node IDs require CUDA driver 13.1 or newer") + raise NotImplementedError("Graph IDs require a CUDA 13 build of cuda.core and CUDA driver 13.1 or newer") @property def tools_id(self) -> int: """The node's ID reported by CUDA profiling and tooling interfaces. + + Requires CUDA 13 build and driver 13.1+ """ GN_check_valid(self) if self._is_entry: @@ -174,12 +178,12 @@ cdef class GraphNode: IF CUDA_CORE_BUILD_MAJOR >= 13: cdef unsigned long long node_id if cy_driver_version() < (13, 1, 0): - raise NotImplementedError("Graph node IDs require CUDA driver 13.1 or newer") + raise NotImplementedError("Graph IDs require a CUDA 13 build of cuda.core and CUDA driver 13.1 or newer") with nogil: HANDLE_RETURN(cydriver.cuGraphNodeGetToolsId(as_cu(self._h_node), &node_id)) return node_id ELSE: - raise NotImplementedError("Graph node IDs require CUDA driver 13.1 or newer") + raise NotImplementedError("Graph IDs require a CUDA 13 build of cuda.core and CUDA driver 13.1 or newer") @property def graph(self) -> GraphDefinition: diff --git a/cuda_core/docs/source/release/1.3.0-notes.rst b/cuda_core/docs/source/release/1.3.0-notes.rst index d9ab9014473..616adf9e692 100644 --- a/cuda_core/docs/source/release/1.3.0-notes.rst +++ b/cuda_core/docs/source/release/1.3.0-notes.rst @@ -46,8 +46,8 @@ New features ------------ - Added read-only ``GraphDefinition.id``, ``Graph.id``, ``GraphNode.local_id`` - and ``GraphNode.tools_id`` properties (CUDA 13.1+), and - ``KernelAttributes.device_node_update_supported`` (CUDA 13.3+). + and ``GraphNode.tools_id`` properties (CUDA 13 build and driver 13.1+), and + ``KernelAttributes.device_node_update_supported`` (CUDA 13 build and driver 13.3+). The existing ``GraphNode.graph`` property provides containing-graph navigation. (`#2360 `__) diff --git a/cuda_core/tests/graph/test_graph_definition.py b/cuda_core/tests/graph/test_graph_definition.py index 1a5d3ad80b5..cd4f5038bd7 100644 --- a/cuda_core/tests/graph/test_graph_definition.py +++ b/cuda_core/tests/graph/test_graph_definition.py @@ -812,7 +812,7 @@ def test_graphdef_handle_valid(init_cuda): def test_graph_identity_attributes(init_cuda): - from cuda.core._utils.version import driver_version + from cuda.core._utils.version import BUILD_CUDA_MAJOR, driver_version definition = GraphDefinition() node = definition.empty() @@ -820,11 +820,15 @@ def test_graph_identity_attributes(init_cuda): graph = definition.instantiate() try: - if driver_version() < (13, 1, 0): + if BUILD_CUDA_MAJOR < 13 or driver_version() < (13, 1, 0): with pytest.raises(NotImplementedError): _ = definition.id with pytest.raises(NotImplementedError): _ = graph.id + with pytest.raises(NotImplementedError): + _ = node.local_id + with pytest.raises(NotImplementedError): + _ = node.tools_id return assert isinstance(definition.id, int) assert isinstance(graph.id, int) diff --git a/cuda_core/tests/test_module.py b/cuda_core/tests/test_module.py index c2a912fcf57..0e2ac833124 100644 --- a/cuda_core/tests/test_module.py +++ b/cuda_core/tests/test_module.py @@ -345,6 +345,19 @@ def test_read_only_kernel_attributes(get_saxpy_kernel_cubin, attr, expected_type assert isinstance(value, expected_type), f"Expected {attr} to be of type {expected_type}, but got {type(value)}" +def test_device_node_update_supported(get_saxpy_kernel_cubin): + from cuda.core._utils.version import BUILD_CUDA_MAJOR, driver_version + + kernel, _ = get_saxpy_kernel_cubin + + for device in Device.get_all_devices(): + if BUILD_CUDA_MAJOR < 13 or driver_version() < (13, 3, 0): + with pytest.raises(NotImplementedError): + _ = kernel.attributes[device].device_node_update_supported + else: + assert isinstance(kernel.attributes[device].device_node_update_supported, bool) + + def test_object_code_load_ptx(get_saxpy_kernel_ptx): ptx, mod = get_saxpy_kernel_ptx sym_map = mod.symbol_mapping