From f12896332d6309e2170e34987974f6cc380c22a1 Mon Sep 17 00:00:00 2001 From: Andy Jost Date: Mon, 26 Oct 2026 14:57:29 -0700 Subject: [PATCH] refactor(cuda.core): rename VirtualMemoryIPCBufferDescriptor to VirtualMemoryFdBufferDescriptor The class carries POSIX file descriptors for VirtualMemoryResource buffers. A fabric-handle descriptor will sit beside it, so its name now says which transport it is. No alias: the class first appears in the unreleased 1.3.0. No behavior change. Written by Codex (gpt-6.1-sol); reviewed by Claude. Co-Authored-By: Claude Fable 5.1 --- cuda_core/cuda/core/_cpp/rt/VMM_DESIGN.md | 4 ++-- cuda_core/cuda/core/_memory/_ipc.pxd | 2 +- cuda_core/cuda/core/_memory/_ipc.pyi | 6 +++--- cuda_core/cuda/core/_memory/_ipc.pyx | 16 ++++++++-------- .../core/_memory/_virtual_memory_resource.pyi | 8 ++++---- .../core/_memory/_virtual_memory_resource.pyx | 12 ++++++------ cuda_core/docs/source/api_private.rst | 2 +- cuda_core/docs/source/release/1.3.0-notes.rst | 2 +- cuda_core/tests/memory_ipc/test_vmm_ipc.py | 10 +++++----- 9 files changed, 31 insertions(+), 31 deletions(-) diff --git a/cuda_core/cuda/core/_cpp/rt/VMM_DESIGN.md b/cuda_core/cuda/core/_cpp/rt/VMM_DESIGN.md index 2797af2a5c8..ce1f9dab90b 100644 --- a/cuda_core/cuda/core/_cpp/rt/VMM_DESIGN.md +++ b/cuda_core/cuda/core/_cpp/rt/VMM_DESIGN.md @@ -259,7 +259,7 @@ descriptor either; it records only that it was imported (`is_mapped`). A descriptor parked in a `Queue` or sent to a `Pool` pins the memory in the sender until the receiver unpickles it. Besides `multiprocessing`, a process with its own file descriptor passing sends the descriptor's `fds`, `sizes`, -and `size` and rebuilds it with `VirtualMemoryIPCBufferDescriptor.from_fds()`, +and `size` and rebuilds it with `VirtualMemoryFdBufferDescriptor.from_fds()`, which duplicates the integers it is given and always builds a `posix_fd` descriptor. @@ -304,7 +304,7 @@ importer needs access to the exporter's IMEX channel rather than a matching device index, and the memory may live on another node. The file-descriptor rules above (ownership, pinning, `pickle` raising, the same-device check) do not hold for it, so fabric sharing gets a descriptor class of its own instead -of a widened `VirtualMemoryIPCBufferDescriptor`, whose `handles` stay +of a widened `VirtualMemoryFdBufferDescriptor`, whose `handles` stay `IPCAllocationHandle`s. `from_fds()` is POSIX-only by construction for the same reason and takes no handle type; a fabric descriptor is plain data and needs no out-of-band constructor. Tracked on the VMM epic (#2980). diff --git a/cuda_core/cuda/core/_memory/_ipc.pxd b/cuda_core/cuda/core/_memory/_ipc.pxd index 7d2feb57271..75d41c51193 100644 --- a/cuda_core/cuda/core/_memory/_ipc.pxd +++ b/cuda_core/cuda/core/_memory/_ipc.pxd @@ -55,7 +55,7 @@ cdef class IPCAllocationHandle: # Descriptor of a VirtualMemoryResource buffer: one exported handle per # physical allocation that backs the buffer, in address order. -cdef class VirtualMemoryIPCBufferDescriptor(IPCBufferDescriptor): +cdef class VirtualMemoryFdBufferDescriptor(IPCBufferDescriptor): cdef readonly int _handle_type cdef readonly tuple _chunk_sizes cdef readonly tuple _handles diff --git a/cuda_core/cuda/core/_memory/_ipc.pyi b/cuda_core/cuda/core/_memory/_ipc.pyi index 6ead5878d73..ffc3f39f602 100644 --- a/cuda_core/cuda/core/_memory/_ipc.pyi +++ b/cuda_core/cuda/core/_memory/_ipc.pyi @@ -58,7 +58,7 @@ class IPCAllocationHandle: @property def uuid(self) -> uuid.UUID: ... -class VirtualMemoryIPCBufferDescriptor(IPCBufferDescriptor): +class VirtualMemoryFdBufferDescriptor(IPCBufferDescriptor): """Serializable object describing a :class:`VirtualMemoryBuffer` that can be shared between processes. The descriptor holds one exported POSIX file descriptor per physical @@ -97,9 +97,9 @@ class VirtualMemoryIPCBufferDescriptor(IPCBufferDescriptor): _handles: tuple[Any, ...] @staticmethod - def _from_exports(handle_type: int, chunk_sizes: tuple[int, ...], handles: tuple[Any, ...], size: int) -> VirtualMemoryIPCBufferDescriptor: ... + def _from_exports(handle_type: int, chunk_sizes: tuple[int, ...], handles: tuple[Any, ...], size: int) -> VirtualMemoryFdBufferDescriptor: ... @classmethod - def from_fds(cls, fds: Iterable[int | IPCAllocationHandle], sizes: Iterable[int], *, size: int | None=None) -> VirtualMemoryIPCBufferDescriptor: + def from_fds(cls, fds: Iterable[int | IPCAllocationHandle], sizes: Iterable[int], *, size: int | None=None) -> VirtualMemoryFdBufferDescriptor: """Build a descriptor from POSIX file descriptors received outside ``multiprocessing``. The exporter sends ``fds``, ``sizes``, and ``size`` of its descriptor diff --git a/cuda_core/cuda/core/_memory/_ipc.pyx b/cuda_core/cuda/core/_memory/_ipc.pyx index 59814314720..5091d39f0fc 100644 --- a/cuda_core/cuda/core/_memory/_ipc.pyx +++ b/cuda_core/cuda/core/_memory/_ipc.pyx @@ -177,7 +177,7 @@ def _reconstruct_allocation_handle(cls: type, df: object, uuid: uuid.UUID | None multiprocessing.reduction.register(IPCAllocationHandle, _reduce_allocation_handle) -cdef class VirtualMemoryIPCBufferDescriptor(IPCBufferDescriptor): +cdef class VirtualMemoryFdBufferDescriptor(IPCBufferDescriptor): """Serializable object describing a :class:`VirtualMemoryBuffer` that can be shared between processes. The descriptor holds one exported POSIX file descriptor per physical @@ -215,9 +215,9 @@ cdef class VirtualMemoryIPCBufferDescriptor(IPCBufferDescriptor): @staticmethod def _from_exports( handle_type: int, chunk_sizes: tuple[int, ...], handles: tuple, size: int - ) -> VirtualMemoryIPCBufferDescriptor: - cdef VirtualMemoryIPCBufferDescriptor self = VirtualMemoryIPCBufferDescriptor.__new__( - VirtualMemoryIPCBufferDescriptor) + ) -> VirtualMemoryFdBufferDescriptor: + cdef VirtualMemoryFdBufferDescriptor self = VirtualMemoryFdBufferDescriptor.__new__( + VirtualMemoryFdBufferDescriptor) self._payload = b"" self._size = size self._handle_type = handle_type @@ -232,7 +232,7 @@ cdef class VirtualMemoryIPCBufferDescriptor(IPCBufferDescriptor): sizes: Iterable[int], *, size: int | None = None, - ) -> VirtualMemoryIPCBufferDescriptor: + ) -> VirtualMemoryFdBufferDescriptor: """Build a descriptor from POSIX file descriptors received outside ``multiprocessing``. The exporter sends ``fds``, ``sizes``, and ``size`` of its descriptor @@ -292,7 +292,7 @@ cdef class VirtualMemoryIPCBufferDescriptor(IPCBufferDescriptor): raise # The handle owns the duplicate now; if append fails, the handle closes it once. handles.append(handle) - return VirtualMemoryIPCBufferDescriptor._from_exports(driver_type, sizes_t, tuple(handles), size) + return VirtualMemoryFdBufferDescriptor._from_exports(driver_type, sizes_t, tuple(handles), size) @property def handle_type(self) -> VirtualMemoryHandleType: @@ -330,7 +330,7 @@ cdef class VirtualMemoryIPCBufferDescriptor(IPCBufferDescriptor): def __reduce__(self) -> tuple[object, ...]: # multiprocessing duplicates the IPCAllocationHandle fds into the receiver; plain pickle raises. - return VirtualMemoryIPCBufferDescriptor._from_exports, ( + return VirtualMemoryFdBufferDescriptor._from_exports, ( self._handle_type, self._chunk_sizes, self._handles, self._size) @@ -359,7 +359,7 @@ cdef Buffer Buffer_from_ipc_descriptor( cls, object mr, IPCBufferDescriptor ipc_descriptor, stream ): """Import a buffer that was exported from another process.""" - if isinstance(ipc_descriptor, VirtualMemoryIPCBufferDescriptor): + if isinstance(ipc_descriptor, VirtualMemoryFdBufferDescriptor): # Imported here rather than cimported: _virtual_memory_resource # cimports this module. from cuda.core._memory._virtual_memory_resource import VirtualMemoryResource diff --git a/cuda_core/cuda/core/_memory/_virtual_memory_resource.pyi b/cuda_core/cuda/core/_memory/_virtual_memory_resource.pyi index a01434cee90..d7b62853451 100644 --- a/cuda_core/cuda/core/_memory/_virtual_memory_resource.pyi +++ b/cuda_core/cuda/core/_memory/_virtual_memory_resource.pyi @@ -6,7 +6,7 @@ from typing import Iterable from cuda.core._device import Device from cuda.core._memory._buffer import Buffer, MemoryResource -from cuda.core._memory._ipc import VirtualMemoryIPCBufferDescriptor +from cuda.core._memory._ipc import VirtualMemoryFdBufferDescriptor from cuda.core._stream import Stream from cuda.core._utils.cuda_utils import driver from cuda.core.graph import GraphBuilder @@ -98,7 +98,7 @@ class VirtualMemoryBuffer(Buffer): freed when the last buffer that maps it closes. """ @property - def ipc_descriptor(self) -> VirtualMemoryIPCBufferDescriptor: + def ipc_descriptor(self) -> VirtualMemoryFdBufferDescriptor: """A new descriptor for sharing this buffer with other processes. Every access exports the physical allocations that back the buffer @@ -205,7 +205,7 @@ class VirtualMemoryResource(MemoryResource): is not visible. Plain ``pickle`` cannot carry the file descriptors; a process with its own file descriptor passing sends the descriptor's ``fds``, ``sizes``, and ``size`` and rebuilds it with - ``VirtualMemoryIPCBufferDescriptor.from_fds()``. The importing resource + ``VirtualMemoryFdBufferDescriptor.from_fds()``. The importing resource maps the memory for its device and the devices in its ``peers`` option, with its own access options. A descriptor pins the physical memory while it exists, in every process that holds one, and nothing else does. A @@ -346,7 +346,7 @@ class VirtualMemoryResource(MemoryResource): (``location_type`` ``"host"``, ``"host_numa"``, or ``"host_numa_current"``) is not shared yet. """ - def _import_ipc_buffer(self, desc: VirtualMemoryIPCBufferDescriptor, stream) -> VirtualMemoryBuffer: + def _import_ipc_buffer(self, desc: VirtualMemoryFdBufferDescriptor, stream) -> VirtualMemoryBuffer: """Import a buffer that another process exported; see :meth:`Buffer.from_ipc_descriptor`. Every exported allocation is imported with this resource's handle diff --git a/cuda_core/cuda/core/_memory/_virtual_memory_resource.pyx b/cuda_core/cuda/core/_memory/_virtual_memory_resource.pyx index 12add34afe5..512953f117b 100644 --- a/cuda_core/cuda/core/_memory/_virtual_memory_resource.pyx +++ b/cuda_core/cuda/core/_memory/_virtual_memory_resource.pyx @@ -18,7 +18,7 @@ from cuda.core._memory._buffer cimport ( from cuda.core._memory._ipc cimport ( IPCAllocationHandle, IPCDataForBuffer, - VirtualMemoryIPCBufferDescriptor, + VirtualMemoryFdBufferDescriptor, ) from cuda.core._rt cimport ( ContextHandle, @@ -296,7 +296,7 @@ cdef class VirtualMemoryBuffer(Buffer): """ @property - def ipc_descriptor(self) -> VirtualMemoryIPCBufferDescriptor: + def ipc_descriptor(self) -> VirtualMemoryFdBufferDescriptor: """A new descriptor for sharing this buffer with other processes. Every access exports the physical allocations that back the buffer @@ -439,7 +439,7 @@ cdef class VirtualMemoryResource(MemoryResource): is not visible. Plain ``pickle`` cannot carry the file descriptors; a process with its own file descriptor passing sends the descriptor's ``fds``, ``sizes``, and ``size`` and rebuilds it with - ``VirtualMemoryIPCBufferDescriptor.from_fds()``. The importing resource + ``VirtualMemoryFdBufferDescriptor.from_fds()``. The importing resource maps the memory for its device and the devices in its ``peers`` option, with its own access options. A descriptor pins the physical memory while it exists, in every process that holds one, and nothing else does. A @@ -916,7 +916,7 @@ cdef class VirtualMemoryResource(MemoryResource): and self.config.location_type not in _HOST_LOCATION_TYPES ) - def _import_ipc_buffer(self, VirtualMemoryIPCBufferDescriptor desc not None, stream) -> VirtualMemoryBuffer: + def _import_ipc_buffer(self, VirtualMemoryFdBufferDescriptor desc not None, stream) -> VirtualMemoryBuffer: """Import a buffer that another process exported; see :meth:`Buffer.from_ipc_descriptor`. Every exported allocation is imported with this resource's handle @@ -1092,7 +1092,7 @@ def _reconstruct_virtual_memory_resource( return cls(device, replace(config, peers=peers)) -cdef VirtualMemoryIPCBufferDescriptor _export_ipc_descriptor(Buffer buf): +cdef VirtualMemoryFdBufferDescriptor _export_ipc_descriptor(Buffer buf): """Export the allocations that back ``buf`` as shareable handles, in address order. Only the allocations that cover ``buf.size`` are exported; a buffer's size @@ -1154,4 +1154,4 @@ cdef VirtualMemoryIPCBufferDescriptor _export_ipc_descriptor(Buffer buf): # The handle owns the fd now; if append fails, the handle closes it once. handles.append(handle) sizes.append(chunk) - return VirtualMemoryIPCBufferDescriptor._from_exports(handle_type, tuple(sizes), tuple(handles), buf._size) + return VirtualMemoryFdBufferDescriptor._from_exports(handle_type, tuple(sizes), tuple(handles), buf._size) diff --git a/cuda_core/docs/source/api_private.rst b/cuda_core/docs/source/api_private.rst index 9ce599d05d6..bc8c511b356 100644 --- a/cuda_core/docs/source/api_private.rst +++ b/cuda_core/docs/source/api_private.rst @@ -48,7 +48,7 @@ CUDA runtime _device.DeviceProperties _memory._ipc.IPCAllocationHandle _memory._ipc.IPCBufferDescriptor - _memory._ipc.VirtualMemoryIPCBufferDescriptor + _memory._ipc.VirtualMemoryFdBufferDescriptor _memory._managed_buffer.AccessedBySetProxy 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 f63ce1f1cff..ca89985cf43 100644 --- a/cuda_core/docs/source/release/1.3.0-notes.rst +++ b/cuda_core/docs/source/release/1.3.0-notes.rst @@ -97,7 +97,7 @@ New features physical allocation and pins the memory while it exists; nothing else does. A buffer that contains imported memory cannot be exported again. For a transport of your own, the descriptor exposes ``fds``, ``sizes``, and - ``size``, and ``VirtualMemoryIPCBufferDescriptor.from_fds()`` rebuilds it + ``size``, and ``VirtualMemoryFdBufferDescriptor.from_fds()`` rebuilds it in the receiver. Fabric handles are not shared yet. (`#2980 `__) diff --git a/cuda_core/tests/memory_ipc/test_vmm_ipc.py b/cuda_core/tests/memory_ipc/test_vmm_ipc.py index 8bf149b0055..3db6476c94a 100644 --- a/cuda_core/tests/memory_ipc/test_vmm_ipc.py +++ b/cuda_core/tests/memory_ipc/test_vmm_ipc.py @@ -30,7 +30,7 @@ from cuda.bindings import driver from cuda.core import Buffer, Device, MemoryResource, VirtualMemoryResource, VirtualMemoryResourceOptions from cuda.core._dlpack import DLDeviceType -from cuda.core._memory._ipc import IPCAllocationHandle, IPCBufferDescriptor, VirtualMemoryIPCBufferDescriptor +from cuda.core._memory._ipc import IPCAllocationHandle, IPCBufferDescriptor, VirtualMemoryFdBufferDescriptor from cuda.core._memory._virtual_memory_resource import VirtualMemoryBuffer from cuda.core._utils.cuda_utils import CUDAError, handle_return from cuda.core.utils import StridedMemoryView @@ -113,7 +113,7 @@ def _forge(desc, **fields): fields.setdefault("chunk_sizes", desc._chunk_sizes) fields.setdefault("handles", desc._handles) fields.setdefault("size", desc.size) - return VirtualMemoryIPCBufferDescriptor._from_exports( + return VirtualMemoryFdBufferDescriptor._from_exports( fields["handle_type"], fields["chunk_sizes"], fields["handles"], fields["size"] ) @@ -812,7 +812,7 @@ def test_round_trip_with_os_dup(self, vmm_ipc_device): del desc gc.collect() assert _open_fds() == fds0 + 2 - rebuilt = VirtualMemoryIPCBufferDescriptor.from_fds(wire["fds"], wire["sizes"], size=wire["size"]) + rebuilt = VirtualMemoryFdBufferDescriptor.from_fds(wire["fds"], wire["sizes"], size=wire["size"]) assert _open_fds() == fds0 + 4, "from_fds duplicates the integers it is given" for fd in wire["fds"]: os.close(fd) # the caller keeps ownership of its own @@ -838,7 +838,7 @@ def test_from_fds_shares_handle_objects_and_rejects_bad_input(self, vmm_ipc_devi buf = mr.allocate(1) gran = buf.size desc = buf.ipc_descriptor - from_fds = VirtualMemoryIPCBufferDescriptor.from_fds + from_fds = VirtualMemoryFdBufferDescriptor.from_fds shared = from_fds(desc.handles, desc.sizes) assert shared.handles[0] is desc.handles[0] # an IPCAllocationHandle is shared, not duplicated @@ -898,7 +898,7 @@ def child_main(device_id, sock, queue): with sock: msg, fds, _flags, _addr = socket.recv_fds(sock, 4096, 16) header = json.loads(msg) - desc = VirtualMemoryIPCBufferDescriptor.from_fds(fds, header["sizes"], size=header["size"]) + desc = VirtualMemoryFdBufferDescriptor.from_fds(fds, header["sizes"], size=header["size"]) for fd in fds: os.close(fd) # from_fds duplicated them; the received ones are ours to close imported = Buffer.from_ipc_descriptor(_resource(device), desc, stream=device.default_stream)