Skip to content

feat(cuda.core): share VirtualMemoryResource buffers with fabric handles - #3230

Open
Andy-Jost wants to merge 14 commits into
NVIDIA:mainfrom
Andy-Jost:ajost/vmm-fabric
Open

Andy-Jost wants to merge 14 commits into
NVIDIA:mainfrom
Andy-Jost:ajost/vmm-fabric

Conversation

@Andy-Jost

@Andy-Jost Andy-Jost commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Buffers of a VirtualMemoryResource configured with handle_type="fabric" can now be shared between processes on one node. This adds the fabric transport that #2980 tracks, beside the POSIX fd transport from #3028.

Changes

  • New VirtualMemoryFabricBufferDescriptor (listed in api_private.rst): one opaque 64-byte CUmemFabricHandle per physical allocation, the allocation sizes, the buffer size, and the exporting device's UUID. It is plain data: pickle and multiprocessing carry it without the file-descriptor machinery, it compares and hashes by value, and from_handles() rebuilds one received through a transport of your own, with validation. The export zeroes the handle struct first, so two exports of one allocation carry the same bytes and no stack bytes travel in a descriptor.
  • Both VMM descriptors derive from a private _VirtualMemoryDescriptor, so Buffer.from_ipc_descriptor and the resource's import run one loop for both transports. The fd descriptor keeps its ownership and identity semantics and its from_fds().
  • VirtualMemoryResource construction checks Device.properties.handle_type_fabric_supported for handle_type="fabric" and raises RuntimeError that names the NVLink fabric and IMEX channel requirements, before an allocation can fail opaquely. A device can report support while the allocation is refused (the attribute does not check for an NVLink fabric, and older drivers do not check for an IMEX channel); a refused allocation then carries a note that says so. is_ipc_enabled is True for "fabric" on Linux with device-located memory.
  • Fabric descriptors pin nothing. The exporter keeps the buffer alive until every importer has imported it; after import, the imported allocation holds its own driver references. A stale or forged handle fails at import with a driver error and a note about stale handles, forgery, and IMEX channels. The docstrings, the release note, and VMM_DESIGN.md say so wherever descriptor lifetime is described.
  • A location mismatch at import names the owning device by UUID and says which local device it is, or that it is not visible in this process.
  • _ipc.pyi and _virtual_memory_resource.pyi are regenerated by the stub hook.
  • Tests: tests/memory_ipc/test_vmm_fabric.py covers export shape, descriptor validation and pickling, Queue, Pipe, Process-argument, and Pool round trips for descriptors and buffers, a second-GPU import with peer access, handle-type mismatch, garbage and stale handles, re-export of imports, a queued buffer that does not pin, and the unsupported-device error. The fabric fixtures skip on devices without fabric handle support, and on devices that report it but refuse the allocation (one probe allocation per device).

Validation

Fabric handles need an NVLink fabric and an accessible IMEX channel. The project's CI has no such runner, so the fabric cases skip there; the release note says that this release's fabric support is not covered by CI. On the CI runners the attribute is true while every fabric allocation is refused with a driver error: the runner VMs disable NVLink and have no IMEX channel, and the attribute checks neither on those drivers. That is why the fixtures probe instead of trusting the attribute.

Validation on NVIDIA internal hardware: a two-GPU B300 system ran the memory_ipc suite and test_memory.py twice: on the first commit (478 passed, 21 skipped; the one failure found the uninitialized padding in the exported handle struct) and on the fix and on the PR head with main merged (479 passed, 21 skipped each), and a Hopper system without fabric support ran the fabric and fd suites (30 passed, 17 skipped, with the unsupported-device error test among the passes). The fabric suite also passed inside a container on the B300 system (a stock CUDA base image with the GPUs injected by the NVIDIA container CLI and the IMEX channel device node mounted; 18 passed, 1 skipped, three runs). Multi-node sharing is out of scope and untested.

Related Work

Part of #2980. Follows #3028 and #3229; this PR includes the #3229 commit until that PR merges.

🤖 Generated with Claude Code

Andy-Jost and others added 2 commits October 26, 2026 14:57
…alMemoryFdBufferDescriptor

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 <noreply@anthropic.com>
Add VirtualMemoryFabricBufferDescriptor, a plain-data descriptor that
carries one opaque 64-byte CUmemFabricHandle per physical allocation,
the allocation sizes, the buffer size, and the exporting device's UUID.
VirtualMemoryResource exports it when config.handle_type is "fabric",
and Buffer.from_ipc_descriptor imports it through the shared
_VirtualMemoryDescriptor interface that the POSIX fd descriptor also
implements, so both transports run one import loop.

Fabric descriptors travel through plain pickle and multiprocessing
without the file-descriptor machinery and pin nothing: the exporter
keeps the buffer alive until every importer has imported it. A stale or
forged handle fails at import with a driver error and a note. Resource
construction checks Device.properties.handle_type_fabric_supported and
raises RuntimeError when the device lacks an NVLink fabric or an
accessible IMEX channel. from_handles() rebuilds a descriptor received
through a transport of your own. A location mismatch at import names
the owning device by UUID.

Sharing is supported on one node; multi-node sharing is untested. The
project's CI has no fabric-capable runner; the release note says so.

Part of NVIDIA#2980.

Written by Codex (gpt-6.1-sol); reviewed by Claude.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@Andy-Jost Andy-Jost added this to the cuda.core 1.3.0 milestone Oct 26, 2026
@Andy-Jost Andy-Jost added P0 High priority - Must do! feature New feature or request cuda.core Everything related to the cuda.core module labels Oct 26, 2026
@Andy-Jost Andy-Jost self-assigned this Oct 26, 2026
@coderabbitai

coderabbitai Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Explain Change →

No actionable comments were generated in the recent review.

Summary

Summary by CodeRabbit

  • New Features
    • Linux virtual-memory sharing for device memory now supports fabric handles alongside POSIX file descriptors.
    • Fabric descriptors can be pickled and transferred between processes on the same node. They do not pin allocations, so keep the exporting buffer alive until import completes. Imported buffers cannot be re-exported.
    • Fabric sharing requires a supported device, NVLink fabric, and an accessible IMEX channel. Unsupported configurations and invalid or incompatible imports produce errors.
  • API Updates
    • VirtualMemoryFabricBufferDescriptor is available for fabric handles; VirtualMemoryFdBufferDescriptor remains available for POSIX file descriptors.

Linux virtual-memory IPC now supports fabric handles alongside POSIX file descriptors. The change adds fabric descriptors and resource export and import paths, documents handle lifetime and requirements, and adds tests for transfers, validation, errors, and unsupported devices.

Changes: Linux VMM Fabric IPC

Layer / File(s) Summary
Shared and fabric descriptor model
cuda_core/cuda/core/_memory/_ipc.pxd, cuda_core/cuda/core/_memory/_ipc.pyi, cuda_core/cuda/core/_memory/_ipc.pyx
A shared descriptor base provides handle type, allocation sizes, and indexed handle access. VirtualMemoryFabricBufferDescriptor validates and serializes fabric handles, sizes, and optional owner UUID metadata.
Resource export and import
cuda_core/cuda/core/_memory/_virtual_memory_resource.pyx, cuda_core/cuda/core/_memory/_virtual_memory_resource.pyi, cuda_core/cuda/core/_cpp/rt/VMM_DESIGN.md, cuda_core/docs/source/api_private.rst, cuda_core/docs/source/release/1.3.0-notes.rst
Linux resource handling recognizes both handle types. Fabric export returns a fabric descriptor, and import uses the shared descriptor interface. Fabric descriptors do not pin allocations; the exporter must keep the buffer alive until import. Resource construction raises RuntimeError when the device reports no fabric-handle support.
Fabric sharing validation
cuda_core/tests/conftest.py, cuda_core/tests/memory_ipc/test_vmm_fabric.py, cuda_core/tests/memory_ipc/test_vmm_ipc.py, cuda_core/tests/memory_ipc/test_errors.py
Tests cover descriptor construction, serialization, cross-process sharing, ownership, lifetime, import errors, and unsupported devices. Existing VMM descriptor tests use the updated _from_exports signature.

Possibly related issues

Possibly related PRs

  • NVIDIA/cuda-python#3229: Renames the POSIX descriptor to VirtualMemoryFdBufferDescriptor, which this change extends with a shared descriptor base and a separate fabric descriptor.
  • NVIDIA/cuda-python#3034: Updates the same 1.3.0 release documentation for VMM IPC.
  • NVIDIA/cuda-python#3126: Reconstructs resource owner and peer devices by UUID, relevant to fabric imports through a receiving resource.

Suggested reviewers: rwgk, mdboom

Change: Feature

Merge Risk: Minimal · up to 91059

The release note now gives transport-specific guidance, and no remaining issue identified here prevents merging after normal checks.

Security architecture risk: Low · up to 91059

The new transport preserves device, access-policy, size-validation, and cleanup controls. No introduced security defect was established. Fabric handles are copyable sharing capabilities, however, and safe use depends on driver-enforced isolation and keeping the exporting buffer alive until import completes.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The exposed assets are the physical GPU allocations represented by a descriptor and their mappings on importer-configured devices and peers. Handles are allocation-level sharing capabilities, not a tenant identity or logical-buffer authorization mechanism. Effective cross-tenant reach depends on driver and IMEX deployment controls not visible here.

Security Findings and Attack Paths

  • inferred — Copying or forwarding a valid fabric descriptor lets another holder request a driver import without POSIX descriptor passing. That is the intended new capability path; repository evidence does not demonstrate an unauthorized import or an IMEX isolation bypass. The absence of library-level holder authentication alone is not treated as a vulnerability in this low-level sharing API.

Trust Boundaries and Controls

  • observed — Peer-controlled descriptor metadata reaches CUDA import and mapping only after library shape, granularity, overflow, and total-size checks. The actual allocation location is checked against driver-returned properties, while owner UUID affects diagnostics. These importer controls predate fabric support and remain in the shared path.
  • observed — Buffer unpickling performs a live IPC import and explicitly requires a trusted source. Fabric's plain-data transport does not make arbitrary pickle input safe.

Resilience and Maintainability Implications

  • observed — Mapping setup unmaps on access-configuration failure, and mapping destruction unmaps before releasing allocation and reservation references. Fabric test source covers invalid and stale handles, continued importer access after exporter closure, and refusal to re-export imported derivatives; these tests were not executed during this assessment.

Hardening Proposals

  • proposed — Applications using fabric sharing should transport descriptor bytes as sensitive capabilities to authenticated recipients and use an import acknowledgment before releasing the exporter. This is integration guidance, not an observed missing library control.
- [ ] Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Tip

🎯 Customize your risk assessments

Guide how CodeRabbit assesses merge risk and security architecture risk. Highlight sensitive changes and explain your security boundaries using Merge Risk Instructions and Security Risk Instructions in your review settings. Security architecture risk assessments require the Advanced plan or above.

✅ Automatic approvals, with your rules

Let CodeRabbit approve pull requests once required threads are resolved, pre-merge checks pass, and your risk limits are met. Enable Automatic approvals in review settings, with overrides for teams or file paths.

Recent review info

Run configuration

Commits

Reviewing files that changed from the base of the PR and between 001192a and 910597a.

Files selected for processing: 6

  • cuda_core/cuda/core/_memory/_virtual_memory_resource.pyi
  • cuda_core/cuda/core/_memory/_virtual_memory_resource.pyx
  • cuda_core/docs/source/api_private.rst
  • cuda_core/docs/source/release/1.3.0-notes.rst
  • cuda_core/tests/memory_ipc/test_errors.py
  • cuda_core/tests/memory_ipc/test_vmm_ipc.py
Files skipped from review as they are similar to previous changes: 1

  • cuda_core/docs/source/api_private.rst

Included review availability: This review used your included allowance. Your plan provides up to 12 included reviews per hour; 11 remain after this review.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1


Review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between 2e6aa4e and e30f0bf.

Files selected for processing: 11
  • cuda_core/cuda/core/_cpp/rt/VMM_DESIGN.md
  • cuda_core/cuda/core/_memory/_ipc.pxd
  • cuda_core/cuda/core/_memory/_ipc.pyi
  • cuda_core/cuda/core/_memory/_ipc.pyx
  • cuda_core/cuda/core/_memory/_virtual_memory_resource.pyi
  • cuda_core/cuda/core/_memory/_virtual_memory_resource.pyx
  • cuda_core/docs/source/api_private.rst
  • cuda_core/docs/source/release/1.3.0-notes.rst
  • cuda_core/tests/conftest.py
  • cuda_core/tests/memory_ipc/test_vmm_fabric.py
  • cuda_core/tests/memory_ipc/test_vmm_ipc.py

Included review availability: This review used your included allowance. Your plan provides up to 12 included reviews per hour; 10 remain after this review.

@github-actions

Copy link
Copy Markdown
Contributor

Zero the 64-byte handle struct before a fabric export. The driver fills
its fields and leaves the padding, so two exports of one buffer carried
different stack bytes (seen on B300); the export now returns the same
bytes for the same allocation, and no stack bytes travel in a descriptor.

The fabric test fixtures allocate once per device after the attribute
check. Inside a container that has the IMEX channel device node the
attribute is true while the GPU has no fabric, and the allocation is
refused; that is what the CI runners do. A refused physical allocation
on a fabric resource now carries a note about the fabric and IMEX
requirements, and the docs say that the attribute can be true where the
allocation still fails.

The import-error tests check cuda.core's note, not the driver's status,
which varies with the IMEX setup. Garbage handles use fixed patterns
instead of os.urandom. The release note names the POSIX fd descriptor
as the one that pins. One note per import failure. _handles is readonly
on both descriptors.

Written by Claude after the de novo review, CodeRabbit, CI, and the
Hopper and B300 runs.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2


Review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between e30f0bf and d6846d9.

Files selected for processing: 8
  • cuda_core/cuda/core/_cpp/rt/VMM_DESIGN.md
  • cuda_core/cuda/core/_memory/_ipc.pxd
  • cuda_core/cuda/core/_memory/_ipc.pyi
  • cuda_core/cuda/core/_memory/_virtual_memory_resource.pyi
  • cuda_core/cuda/core/_memory/_virtual_memory_resource.pyx
  • cuda_core/docs/source/release/1.3.0-notes.rst
  • cuda_core/tests/conftest.py
  • cuda_core/tests/memory_ipc/test_vmm_fabric.py
Files skipped from review as they are similar to previous changes: 3
  • cuda_core/docs/source/release/1.3.0-notes.rst
  • cuda_core/cuda/core/_cpp/rt/VMM_DESIGN.md
  • cuda_core/cuda/core/_memory/_virtual_memory_resource.pyi

Included review availability: This review used your included allowance. Your plan provides up to 12 included reviews per hour; 10 remain after this review.

Comment thread cuda_core/tests/conftest.py Resolved
Andy-Jost and others added 4 commits October 26, 2026 16:45
…r helper

Cython reported the stray line as unreachable code, and the wheel builds
treat Cython warnings as errors. The return goes back to the note helper
it belonged to.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The fixture probe skipped every fabric test on any CUDAError from the
probe allocation, which would hide a real failure (an out-of-memory
condition, for one) as 'no fabric here'. It now skips on the statuses
that mean the device has no usable fabric (NOT_PERMITTED on the CI
runners, INVALID_VALUE on an H200 without an IMEX channel, NOT_SUPPORTED)
and lets anything else propagate, per the test guide's rule on
capability probes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1


Review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between bd69003 and 7dc241c.

Files selected for processing: 2
  • cuda_core/tests/conftest.py
  • cuda_core/tests/memory_ipc/test_vmm_ipc.py

Included review availability: This review used your included allowance. Your plan provides up to 12 included reviews per hour; 11 remain after this review.

Comment thread cuda_core/tests/conftest.py Resolved
…bric

Every conflict was the rename that this branch already carried as
f128963; main's version of each conflicted file equals that commit's,
so the branch side was kept.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to GitHub limitations.

⚠️ Outside diff range comments (1)

Minor · 🎯 Functional Correctness · 1.3.0-notes.rst:88-92

cuda_core/docs/source/release/1.3.0-notes.rst:88-92
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

suggestion: Limit the file-descriptor description to "posix_fd". The introduction now includes "fabric" resources, but these sentences still say that every export produces POSIX file descriptors and cannot use plain pickle. A fabric export produces a fabric handle that can travel as data. Separate the two transport descriptions so readers do not apply FD-handling instructions to fabric descriptors. (docs.nvidia.com) As per coding guidelines, “Keep user-facing behaviors coherent with docs and samples, especially around stream semantics, memory ownership, and compile/link flows.”

Source: Coding guidelines


Review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between 7dc241c and 45ed268.

Files selected for processing: 9
  • cuda_core/cuda/core/_cpp/rt/VMM_DESIGN.md
  • cuda_core/cuda/core/_memory/_ipc.pxd
  • cuda_core/cuda/core/_memory/_ipc.pyi
  • cuda_core/cuda/core/_memory/_ipc.pyx
  • cuda_core/cuda/core/_memory/_virtual_memory_resource.pyi
  • cuda_core/cuda/core/_memory/_virtual_memory_resource.pyx
  • cuda_core/docs/source/api_private.rst
  • cuda_core/docs/source/release/1.3.0-notes.rst
  • cuda_core/tests/memory_ipc/test_vmm_ipc.py

Included review availability: This review used your included allowance. Your plan provides up to 12 included reviews per hour; 11 remain after this review.

Andy-Jost and others added 4 commits October 27, 2026 11:52
The fixture probe skipped the fabric tests on three driver statuses from
the whole probe allocation. A status from the address reservation, the
mapping, or the stream setup could therefore pass as 'no fabric here' and
hide a real failure on a fabric-capable device. The probe now skips only
when the exception carries the note that VirtualMemoryResource attaches
to a refused physical allocation with a fabric handle (appended to the
message on Python 3.10), and lets every other CUDAError propagate.

The 1.3.0 release note described every export as a POSIX file
descriptor that plain pickle cannot carry. It now describes the two
transports separately: file descriptors for "posix_fd", plain-data
fabric handles for "fabric".

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ation fails

The docstrings, the allocation note, the release note, and the fixture
comment explained the over-reporting attribute with a container that has
the IMEX channel device node. The CI evidence says otherwise: the runner
VMs disable NVLink and have no channel node, and the attribute is still
true on the r595 and 610 drivers there. The 13.4 driver source adds the
channel subscription to the attribute; no driver checks for an NVLink
fabric. The text now states that, without the container example.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
_IPC_HANDLE_TYPES = (
frozenset({VirtualMemoryHandleType.POSIX_FD, VirtualMemoryHandleType.FABRIC})
if platform.system() == "Linux" else frozenset()
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

One thing I noticed is that there's technically two places that a descriptor... "describes" what it is. It carries an internal _handle_type, and it captures that information in the subclass type. This matters because there's two now and the import guard at line 1047 validates only the field, by comparing it against the resource's configured type. So you can build a bad VirtualMemoryFdBufferDescriptor whose field is forged to say fabric which then dispatches to the fd implementation, which blows up.

The code smell here abstractly is that there is one fact with two representations. The guard asks "does this descriptor agree with this resource?" and never asks "does this descriptor agree with itself?" Internal consistency between the two copies is simply assumed, so the moment they can diverge, the external check validates the wrong thing.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We should make the class the authority

if isinstance(desc, VirtualMemoryFabricBufferDescriptor) != (
        handle_type == <int>cydriver.CU_MEM_HANDLE_TYPE_FABRIC):
    raise ValueError(
        f"the descriptor claims handle_type={str(cfg.handle_type)!r} but carries "
        f"{type(desc).__name__} handles; it was not produced by this resource's transport"
    )

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I refactored this so each subclass defines its handle type, removing the duplicated per-instance state. I generally don’t think we need to defend against users tampering with internal data structures; constructors and API methods should maintain the invariants.


cdef int _raise_allocation_error(const cydriver.CUmemAllocationProp* prop) except -1:
"""Raise the status of a failed physical allocation; a fabric resource gets the IMEX note."""
if prop.requestedHandleTypes == cydriver.CU_MEM_HANDLE_TYPE_FABRIC:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Peek last error here right? If I OOM a fabric resource I should obtain those details id assume.

Suggested change
if prop.requestedHandleTypes == cydriver.CU_MEM_HANDLE_TYPE_FABRIC:
if (prop.requestedHandleTypes == cydriver.CU_MEM_HANDLE_TYPE_FABRIC
and peek_last_error() in (
cydriver.CUDA_ERROR_NOT_PERMITTED,
cydriver.CUDA_ERROR_NOT_SUPPORTED,
cydriver.CUDA_ERROR_INVALID_VALUE,
)):

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Agree. I redid the function signature to make it more direct as well.

allocation holds its own driver references and is independent of the
exporter. Importing a stale or forged handle fails with a driver error.

Sharing is supported on one node; multi-node sharing is untested. Fabric

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The untested thing raises an eyebrow from me. Ideally we have some way of testing the hot paths.

One maybe overkill idea is to simulate the fabric environment by building our own driver library that lies about the situation. Some back and forth with an agent can quickly produce something vibecoded here that works, see the gist below as an example

fabric_sim.md

Something like this is fairly heavy but the three options seem to all be heavy:

  1. ship documented untested code (a little scary feeling given its multi node/ multi GPU critical code)
  2. Deploy real multinode CI infra for a very limited slice of features
  3. Simulate somehow

FWIW, the above gets me from 18 skips down to 1 on a regular machine.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks for putting this together. I agree the CI coverage gap is not ideal, and we have few good options. This approach would provide useful coverage of cuda-core’s integration logic. I'd say the added scope and maintenance burden seem significant enough to warrant a separate discussion and PR, with a chance for others to weigh in. Does that work for you?

)
def test_is_ipc_enabled(vmm_ipc_device, options, expected):
"""Only POSIX file descriptors on device memory have a transport; host-located memory is not shared yet."""
"""POSIX file descriptors on device memory have a transport; host-located memory is not shared yet."""

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This PR trades dropping pytest.param({"handle_type": "fabric"}, False, id="fabric"), from the above for tests that skip unless we're on fabric enabled hardware. The side effect of this is that reverting the central change doesn't cause a test failure. We should just add

pytest.param({"handle_type": "fabric"}, True, id="fabric"),

Back.

mr = _resource(device)
assert mr.is_ipc_enabled
for location in ("host", "host_numa", "host_numa_current"):
host = _resource(device, location_type=location, handle_type=None if location == "host" else "fabric")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I can't see how this test ever runs. Here we're constructing either a host_numa resource with no numa_id or a host_numa_current, both seem to be rejected unconditionally in _check_config. I believe anywhere the fixture doesn't skip this test due to not being on the right hardware, this fails before asserting anything fabric related.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed. A valid host_numa fabric case now checks is_ipc_enabled=False in the configuration test.

fabric, fd = _resource(device), _resource(device, handle_type="posix_fd")
# Empty descriptors would need no import call; even these must reject a mismatch.
for exporting, importing in ((fabric, fd), (fd, fabric)):
with exporting.allocate(0) as buf, pytest.raises(ValueError, match="configured like the exporter's"):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If all we do is allocate(0) this test doesn't appear to need a fabric environment so it need not be present under the skipped tests (if thats the route we choose)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

fixed

prefix = VirtualMemoryFabricBufferDescriptor.from_handles(desc.handles, desc.sizes, size=1)
with Buffer.from_ipc_descriptor(mr, prefix, stream=device.default_stream) as alias:
assert alias.size == 1 < sum(prefix.sizes)
assert not any(hasattr(desc, name) for name in ("fds", "close", "is_closed"))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nit: 2/3rds of the assertion is vacuous, because if this seeks to exclude the fd descriptor, fds is true, close and is_closed are both False.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

fixed



def _notes(exc):
# Python 3.10 appends the note to the message instead of using PEP 678.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Aren't we off 3.10 now?, guessing this can be removed

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good call. This PR was started before we removed the Python 3.10 coverage. I filed #3374 to sweep the code for obsolete Python 3.10 constructs before the release and I'll update this PR to remove these things.

Comment thread cuda_core/tests/conftest.py Outdated
except CUDAError as exc:
# Only a refused physical allocation means "no fabric here" (NOT_PERMITTED on the CI runners,
# INVALID_VALUE on an H200 without an IMEX channel). VirtualMemoryResource attaches its note about
# the fabric and IMEX requirements at that stage alone (on Python 3.10 it lands in the message);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Python 3.10 again

@brandon-b-miller brandon-b-miller left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Negative results (agent attacks)

The refactored POSIX-fd transport held under 54 attacks on real hardware. Mid-loop chunk failures leaked neither file descriptors nor GPU memory; descriptor exhaustion during export rolled back to an exact 63-fd baseline, confirming the code's own claim that "the handle owns the fd now; if append fails, the handle closes it once"; hostile teardown orders, reference cycles, and survival to interpreter shutdown were clean; import from a thread with no CUDA context works; and a five-chunk cross-process round trip verified all 1,310,720 words of a position-dependent pattern, which proves the shared loop maps chunks at the right offsets rather than merely returning a pointer.
Mid-loop unwinding leaks nothing and is symmetric. The import loop runs at lines 1104-1154 and the address reservation is at 1156, after it, so a failure at chunk i > 0 happens with i imported allocations and no reservation. Measured four ways with free device memory from cuMemGetInfo and a live-reservation count — a real Python-level raise (closing an IPCAllocationHandle mid-loop) and a real driver-level failure both returned to baseline exactly, with the 4 MiB mid-test delta showing the measurement could have seen a one-chunk leak.

@brandon-b-miller

Copy link
Copy Markdown
Contributor

This looks pretty good. Found a few places that could use some hardening or are losing some details. Biggest thing is the testing for sure, which seems like the only major decision item from my side.

@brandon-b-miller brandon-b-miller left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM

This branch has not been deployed

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

Labels

cuda.core Everything related to the cuda.core module feature New feature or request P0 High priority - Must do!

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants