Skip to content

UCT/ZE/COPY: Allocate DMA-BUF-exportable memory for RDMA - #11903

Draft
yafshar wants to merge 1 commit into
openucx:masterfrom
intel-staging:fix/ze-dmabuf-exportable-allocation
Draft

yafshar wants to merge 1 commit into
openucx:masterfrom
intel-staging:fix/ze-dmabuf-exportable-allocation

Conversation

@yafshar

@yafshar yafshar commented Sep 4, 2026 •

Copy link
Copy Markdown
Contributor

Depends on #11902, which must merge first. Without it, the ze-host and
ze-managed variants of the test added here abort in protocol initialization.

What?

Level Zero device memory may have to be allocated with external DMA-BUF export
enabled. The ze_copy memory domain advertised ze-host and ze-device in
dmabuf_mem_types and returned a file descriptor from
zeMemGetAllocProperties(), but allocated without an export descriptor.

  • Request DMA-BUF exportability in uct_ze_copy_mem_alloc(), and only for the
    memory types advertised in dmabuf_mem_types, so allocating a type without a
    DMA-BUF path cannot fail because of the descriptor.
  • Add UCX_ZE_COPY_DMABUF, following the cuda_copy and rocm_copy pattern:
    query export support once at md_open() with zeDeviceGetExternalMemoryProperties(),
    fail md_open() when y is requested but unsupported, and advertise dmabuf_mem_types
    and return a DMA-BUF file descriptor only when effectively enabled.
  • Remove the Intel Xe module heuristic from the IB memory domain, which claimed
    plain ibv_reg_mr() could register ze-device memory.
  • Apply the packet-tracer SGE bound whenever the IB memory domain supports
    DMA-BUF registration.

Why?

A DMA-BUF obtained without an export descriptor does not necessarily describe
the requested range. Registration succeeds, the transfer completes, the
completion is UCS_OK, and the payload is wrong. Nothing reports an error at
any layer:

ucx_perftest -t tag_lat -m ze-device -V -s 4194304   # UCX_TLS=rc,ze_copy
ucp_tests.h:166  UCX  ERROR data validation failed at offset 0: got 0x0 expected 0x1

On the tested systems, writes into ze-device memory were unaffected; failures
occurred only in flows where the RDMA device read from ze-device memory. Such
transfers returned UCS_OK, but the destination contained incorrect data.

How?

UCP already routes DMA-BUF registration by combining a provider's dmabuf_mem_types
with an RDMA memory domain's UCT_MD_FLAG_REG_DMABUF. Therefore, removing the
Xe heuristic does not disable the DMA-BUF GPUDirect RDMA path when both capabilities
are available. With UCX_ZE_COPY_DMABUF=n that heuristic made UCP attempt an
ordinary registration which failed with EFAULT instead of staging through ze_copy. Removing
ZE device memory from the IB MD's reg_mem_types also disabled the packet-tracer
bound, hence extending it to any DMA-BUF-capable IB memory domain; otherwise
tracing may dereference device memory from the CPU.

Memory allocated by an application without requesting external export cannot be
repaired by UCX, so UCX_ZE_COPY_DMABUF=n is available to disable DMA-BUF
registration for it.

test_ucp_mem_type_rndv_zcopy sends from memory allocated by
ucp_mem_map(UCP_MEM_MAP_ALLOCATE) to a host buffer using a forced rendezvous
zero-copy lane and verifies a non-zero pattern. It asserts that the source
memory handle is registered on a memory domain used by a rendezvous zero-copy
lane, preventing a staged-only transfer from passing silently, and skips when
that lane cannot register the memory type. It is parameterized over all memory
types and instantiated for rc_x plus rc_x,ze_copy, so CUDA and ROCm are
covered where present and ZE variants skip cleanly where ze_copy is
unavailable. Reverting only the export descriptor makes both the get_zcopy
and put_zcopy ze-device variants fail the pattern check with zeros.

Tested on Intel Arc Pro B60 (Battlemage), rc_mlx5 over RoCE:

  • 27 gtests pass: test_ucp_mem_type_rndv_zcopy (16), test_ucp_proto_ze (1),
    ze_cpy/test_md_dmabuf (1), ze_copy/test_ze_copy_rma (9).
  • ucx_perftest tag_lat -V passes for ze-device, ze-host, ze-managed, host and
    the mixed host/ze-device pairs, including UCX_ZE_COPY_DMABUF=n and =y.
    GPUDirect RDMA is confirmed active with DMA-BUF versus staged with DMABUF=n.

Known limitation: UCT-level ucx_perftest has no DMA-BUF registration path:
uct_perf_md_mem_reg() does not supply a DMA-BUF fd. Before this change,
-x rc_mlx5 -m ze-device relied on the Xe module heuristic and attempted
ibv_reg_mr() on a device pointer; on the tested systems, this failed with
EFAULT. After removing ze-device from the IB MD's reg_mem_types,
uct_perf_test_check_md_support() rejects this invocation up front instead:

    Unsupported memory type ze-device by rc_mlx5/...

This does not imply that ordinary registration is unsupported on every
platform; only that the presence of the Xe module is insufficient evidence of
that capability. Adding DMA-BUF registration to UCT-level perftest is left for
a separate change.

UCP-level perftest is unaffected. The ZE allocator provides no mem_alloc
hook, so UCP allocates the buffer itself through
ucp_mem_map(UCP_MEM_MAP_ALLOCATE) with the requested memory type and
registers it through UCP's DMA-BUF path.

A Level Zero device-memory allocation may need to be created for
external DMA-BUF export before its handle can be used for RDMA. The
ze_copy memory domain advertised ze-device in 'dmabuf_mem_types' and
obtained a file descriptor through zeMemGetAllocProperties(), but
allocated without an export descriptor. On the tested system, registering
a DMA-BUF obtained that way completed successfully, but RDMA reads
returned incorrect data while the transfer reported success.

Request DMA-BUF exportability in uct_ze_copy_mem_alloc(), and only for
the memory types advertised in 'dmabuf_mem_types', so that allocating a
type without a DMA-BUF path cannot fail because of the descriptor.

Add UCX_ZE_COPY_DMABUF, following the cuda_copy and rocm_copy pattern:
query DMA-BUF export support once at md_open() using
zeDeviceGetExternalMemoryProperties(), fail md_open() when 'y' is
requested but unsupported, and advertise 'dmabuf_mem_types' and return a
DMA-BUF descriptor only when it is effectively enabled. Memory allocated
by an application without requesting external export cannot be repaired
by UCX, so 'n' is available to disable DMA-BUF registration for it.

The presence of the Intel Xe module alone does not prove that an IB
memory domain can register Level Zero device memory directly. UCP routes
DMA-BUF registration by combining a provider's 'dmabuf_mem_types' with an
RDMA memory domain's UCT_MD_FLAG_REG_DMABUF. Remove the Intel Xe module
heuristic from the IB memory domain. With UCX_ZE_COPY_DMABUF=n on the
tested system, that heuristic made UCP attempt ordinary registration,
which failed with EFAULT instead of staging through ze_copy. Removing
ZE device memory from the IB MD's 'reg_mem_types' also disables the
packet-tracer bound, so apply the bound whenever the IB memory domain
supports DMA-BUF registration; otherwise tracing may dereference device
memory from the CPU.

Add test_ucp_mem_type_rndv_zcopy, which sends from memory allocated by
ucp_mem_map(UCP_MEM_MAP_ALLOCATE) to a host buffer over a rendezvous
zero-copy lane and verifies a non-zero pattern. It asserts that the
source is registered on the memory domain used by the operation, so a
staged transfer cannot make the test pass silently, and skips when that
lane cannot register the memory type. Reverting only the export
descriptor makes the ze-device variants fail the pattern check with
zeros, in both the get_zcopy and put_zcopy directions.

Tested on Intel Arc Pro B60 Graphics with rc_mlx5 over RoCE: 16 gtest
variants pass, and ucx_perftest tag_lat with -V passes for ze-device,
ze-host and ze-managed, including the DMABUF=n and DMABUF=y configurations.

Signed-off-by: Yaser Afshar <yaser.afshar@intel.com>
@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Starting review — findings will be posted here when done.

@svc-nvidia-pr-review

Copy link
Copy Markdown

test/gtest/ucp/test_ucp_mem_type.cc

The new test only exercises the default (DMABUF=try) path. Per the project test guidance, a new user-facing config that changes behavior should ideally cover both enable and disable paths. Since the whole point of this PR is that DMABUF=n must produce a correct transfer (data actually readable) while try uses the DMA-BUF handle, a variant with UCX_ZE_COPY_DMABUF=n would directly validate the regression this PR targets. Not a blocker, but worth considering.

test/gtest/ucp/test_ucp_mem_type.cc

In md_map_str(): for a remote (dst_md_index) map, the names are looked up in the local context->tl_mds[...], but dst_md_index is in the peer's MD index space, so the printed names can be wrong/misleading. It only affects the diagnostic UCS_TEST_MESSAGE, so it is cosmetic — could be clarified in the message or gated to the local case.

@yafshar

yafshar commented Sep 4, 2026

Copy link
Copy Markdown
Contributor Author

test/gtest/ucp/test_ucp_mem_type.cc

The new test only exercises the default (DMABUF=try) path. Per the project test guidance, a new user-facing config that changes behavior should ideally cover both enable and disable paths. Since the whole point of this PR is that DMABUF=n must produce a correct transfer (data actually readable) while try uses the DMA-BUF handle, a variant with UCX_ZE_COPY_DMABUF=n would directly validate the regression this PR targets. Not a blocker, but worth considering.

test/gtest/ucp/test_ucp_mem_type.cc

In md_map_str(): for a remote (dst_md_index) map, the names are looked up in the local context->tl_mds[...], but dst_md_index is in the peer's MD index space, so the printed names can be wrong/misleading. It only affects the diagnostic UCS_TEST_MESSAGE, so it is cosmetic — could be clarified in the message or gated to the local case.

Thanks for raising both points.

md_map_str(): after tracing the endpoint direction, the existing lookup is correct. The advertised MD index originates in the remote peer's context. For GET, the map comes from rndv_zcopy_md_map(receiver(), true), whose peer is
sender(); for PUT, it contains local indices from sender(). Both therefore belong to sender()'s context, which is already passed to md_map_str().

This also makes the assertion valid: send_memh->md_map is in sender()'s index space, so its intersection with lane_md_map is meaningful because both maps use the same space. I kept the original lookup.

DMABUF=n variant: the intent is right, but on the tested systems the ze-device case in this test would skip rather than validate staging. With DMABUF=n, the IB MD is absent from reg_md_map[ZE_DEVICE], so the lane-registration check skips before transfer:

    DMABUF=try : OK    get lane mds: mlx5_1 | source memh mds: mlx5_1,ze_cpy
    DMABUF=n   : SKIP  the rendezvous zero-copy lane cannot register ze-device memory

Covering the disable path requires a separate payload-only test without the lane-registration requirement, because it validates staging rather than direct DMA-BUF access. I verified manually that ucx_perftest tag_lat -V -m ze-device
passes with UCX_ZE_COPY_DMABUF=n through staging and also passes with the default DMA-BUF path.

Focused staged-path coverage can be added separately.

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

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants