Coverage for cuda/core/_memory/_graph_memory_resource.pyx: 86.25%
80 statements
« prev ^ index » next coverage.py v7.14.1, created at 2026-06-13 01:38 +0000
« prev ^ index » next coverage.py v7.14.1, created at 2026-06-13 01:38 +0000
1# SPDX-FileCopyrightText: Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2#
3# SPDX-License-Identifier: Apache-2.0
5from __future__ import annotations
7from libc.stdint cimport intptr_t
9from cuda.bindings cimport cydriver
10from cuda.core._memory._buffer cimport Buffer, Buffer_from_deviceptr_handle, MemoryResource
11from cuda.core._resource_handles cimport (
12 DevicePtrHandle,
13 deviceptr_alloc_async,
14 get_last_error,
15 as_cu,
16)
18from cuda.core._stream cimport Stream_accept, Stream
19from cuda.core._utils.cuda_utils cimport HANDLE_RETURN
21from functools import cache
22from typing import TYPE_CHECKING
24if TYPE_CHECKING:
25 from cuda.core._device import Device
26 from cuda.core.graph import GraphBuilder
27 from cuda.core.typing import DevicePointerType
29__all__ = ['GraphMemoryResource']
32cdef class GraphMemoryResourceAttributes:
33 cdef:
34 int _device_id
36 def __init__(self, *args, **kwargs) -> None:
37 raise RuntimeError("GraphMemoryResourceAttributes cannot be instantiated directly. Please use MemoryResource APIs.") 1y
39 @classmethod
40 def _init(cls, device_id: int) -> GraphMemoryResourceAttributes:
41 cdef GraphMemoryResourceAttributes self = GraphMemoryResourceAttributes.__new__(cls) 1abce
42 self._device_id = device_id 1abce
43 return self 1abce
45 def __repr__(self) -> str:
46 return f"{self.__class__.__name__}(%s)" % ", ".join( 1e
47 f"{attr}={getattr(self, attr)}" for attr in dir(self) 1de
48 if not attr.startswith("_") 1e
49 )
51 cdef int _getattribute(self, cydriver.CUgraphMem_attribute attr_enum, void* value) except?-1:
52 with nogil: 1abce
53 HANDLE_RETURN(cydriver.cuDeviceGetGraphMemAttribute(self._device_id, attr_enum, value)) 1abce
54 return 0 1abce
56 cdef int _setattribute(self, cydriver.CUgraphMem_attribute attr_enum, void* value) except?-1:
57 with nogil: 1abc
58 HANDLE_RETURN(cydriver.cuDeviceSetGraphMemAttribute(self._device_id, attr_enum, value)) 1abc
59 return 0 1abc
61 @property
62 def reserved_mem_current(self) -> int:
63 """Current amount of backing memory allocated."""
64 cdef cydriver.cuuint64_t value
65 self._getattribute(cydriver.CUgraphMem_attribute.CU_GRAPH_MEM_ATTR_RESERVED_MEM_CURRENT, &value) 1abce
66 return int(value) 1abce
68 @property
69 def reserved_mem_high(self) -> int:
70 """
71 High watermark of backing memory allocated. It can be set to zero to
72 reset it to the current usage.
73 """
74 cdef cydriver.cuuint64_t value
75 self._getattribute(cydriver.CUgraphMem_attribute.CU_GRAPH_MEM_ATTR_RESERVED_MEM_HIGH, &value) 1abce
76 return int(value) 1abce
78 @reserved_mem_high.setter
79 def reserved_mem_high(self, value: int) -> None:
80 if value != 0: 1abc
81 raise AttributeError(f"Attribute 'reserved_mem_high' may only be set to zero (got {value}).") 1abc
82 cdef cydriver.cuuint64_t zero = 0 1abc
83 self._setattribute(cydriver.CUgraphMem_attribute.CU_GRAPH_MEM_ATTR_RESERVED_MEM_HIGH, &zero) 1abc
85 @property
86 def used_mem_current(self) -> int:
87 """Current amount of memory in use."""
88 cdef cydriver.cuuint64_t value
89 self._getattribute(cydriver.CUgraphMem_attribute.CU_GRAPH_MEM_ATTR_USED_MEM_CURRENT, &value) 1abce
90 return int(value) 1abce
92 @property
93 def used_mem_high(self) -> int:
94 """
95 High watermark of memory in use. It can be set to zero to reset it to
96 the current usage.
97 """
98 cdef cydriver.cuuint64_t value
99 self._getattribute(cydriver.CUgraphMem_attribute.CU_GRAPH_MEM_ATTR_USED_MEM_HIGH, &value) 1abce
100 return int(value) 1abce
102 @used_mem_high.setter
103 def used_mem_high(self, value: int) -> None:
104 if value != 0: 1abc
105 raise AttributeError(f"Attribute 'used_mem_high' may only be set to zero (got {value}).") 1abc
106 cdef cydriver.cuuint64_t zero = 0 1abc
107 self._setattribute(cydriver.CUgraphMem_attribute.CU_GRAPH_MEM_ATTR_USED_MEM_HIGH, &zero) 1abc
110cdef class cyGraphMemoryResource(MemoryResource):
111 def __cinit__(self, int device_id) -> None:
112 self._device_id = device_id 1v
114 def allocate(self, size_t size, *, stream: Stream | GraphBuilder) -> Buffer:
115 """
116 Allocate a buffer of the requested size. See documentation for :obj:`~_memory.MemoryResource`.
117 """
118 cdef Stream s = Stream_accept(stream) 1fghopqrstijklmnabc
119 return GMR_allocate(self, size, s) 1fghopqrstijklmnabc
121 def deallocate(
122 self,
123 ptr: DevicePointerType,
124 size_t size,
125 *,
126 stream: Stream | GraphBuilder
127 ) -> None:
128 """
129 Deallocate a buffer of the requested size. See documentation for :obj:`~_memory.MemoryResource`.
130 """
131 cdef Stream s = Stream_accept(stream)
132 return GMR_deallocate(ptr, size, s)
134 def close(self) -> None:
135 """No operation (provided for compatibility)."""
136 pass
138 def trim(self) -> None:
139 """Free unused memory that was cached on the specified device for use with graphs back to the OS."""
140 with nogil: 1abc
141 HANDLE_RETURN(cydriver.cuDeviceGraphMemTrim(self._device_id)) 1abc
143 @property
144 def attributes(self) -> GraphMemoryResourceAttributes:
145 """Asynchronous allocation attributes related to graphs."""
146 return GraphMemoryResourceAttributes._init(self._device_id) 1abce
148 @property
149 def device_id(self) -> int:
150 """The associated device ordinal."""
151 return self._device_id 1ijklmnabcu
153 @property
154 def is_device_accessible(self) -> bool:
155 """Return True. This memory resource provides device-accessible buffers."""
156 return True 1u
158 @property
159 def is_host_accessible(self) -> bool:
160 """Return False. This memory resource does not provide host-accessible buffers."""
161 return False 1u
164class GraphMemoryResource(cyGraphMemoryResource):
165 """
166 A memory resource for memory related to graphs.
168 The only supported operations are allocation, deallocation, and a limited
169 set of status queries.
171 This memory resource should be used when building graphs. Using this when
172 graphs capture is not enabled will result in a runtime error.
174 Conversely, allocating memory from a `DeviceMemoryResource` when graph
175 capturing is enabled results in a runtime error.
177 Parameters
178 ----------
179 device_id: int | Device
180 Device or Device ordinal for which a graph memory resource is obtained.
181 """
183 def __new__(cls, device_id: int | Device) -> GraphMemoryResource:
184 cdef int c_device_id = getattr(device_id, 'device_id', device_id) 1fghowpqrxstijklmnabcuev
185 return cls._create(c_device_id) 1fghowpqrxstijklmnabcuev
187 @classmethod
188 @cache
189 def _create(cls, int device_id) -> GraphMemoryResource:
190 return cyGraphMemoryResource.__new__(cls, device_id) 1v
193# Raise an exception if the given stream is capturing.
194# A result of CU_STREAM_CAPTURE_STATUS_INVALIDATED is considered an error.
195cdef inline int check_capturing(cydriver.CUstream s) except?-1 nogil:
196 cdef cydriver.CUstreamCaptureStatus capturing
197 HANDLE_RETURN(cydriver.cuStreamIsCapturing(s, &capturing)) 1fghopqrstijklmnabc
198 if capturing != cydriver.CUstreamCaptureStatus.CU_STREAM_CAPTURE_STATUS_ACTIVE: 1fghopqrstijklmnabc
199 raise RuntimeError("GraphMemoryResource cannot perform memory operations on " 1fgh
200 "a non-capturing stream.")
203cdef inline Buffer GMR_allocate(cyGraphMemoryResource self, size_t size, Stream stream):
204 cdef cydriver.CUstream s = as_cu(stream._h_stream) 1fghopqrstijklmnabc
205 cdef DevicePtrHandle h_ptr
206 with nogil: 1fghopqrstijklmnabc
207 check_capturing(s) 1fghopqrstijklmnabc
208 h_ptr = deviceptr_alloc_async(size, stream._h_stream) 1fghopqrstijklmnabc
209 if not h_ptr: 1fghopqrstijklmnabc
210 HANDLE_RETURN(get_last_error())
211 raise RuntimeError(
212 f"Failed to allocate {size} bytes from GraphMemoryResource: "
213 "cuda-core returned an empty allocation handle without recording a CUDA error. "
214 "This is an internal cuda-core error; please report it with your CUDA driver, "
215 "CUDA Toolkit, and cuda-python versions."
216 )
217 return Buffer_from_deviceptr_handle(h_ptr, size, self, None) 1fghopqrstijklmnabc
220cdef inline void GMR_deallocate(intptr_t ptr, size_t size, Stream stream) noexcept:
221 cdef cydriver.CUstream s = as_cu(stream._h_stream)
222 cdef cydriver.CUdeviceptr devptr = <cydriver.CUdeviceptr>ptr
223 with nogil:
224 HANDLE_RETURN(cydriver.cuMemFreeAsync(devptr, s))