Skip to content

transport ci : nic amd gpu emulation - #3178

Draft
multiphaseCFD wants to merge 9 commits into
shuli/add-transport-runtime-cifrom
shuli/rdma-nic-amd-gpu-emulation
Draft

multiphaseCFD wants to merge 9 commits into
shuli/add-transport-runtime-cifrom
shuli/rdma-nic-amd-gpu-emulation

Conversation

@multiphaseCFD

Copy link
Copy Markdown
Member

Before submitting

Please complete the following checklist when submitting a PR:

  • All new functions and code must be clearly commented and documented.

  • Ensure that code is properly formatted by running make format.
    The latest version of black and clang-format-20 are used in CI/CD to check formatting.

  • All new features must include a unit test.
    Integration and frontend tests should be added to frontend/test,
    Quantum dialect and MLIR tests should be added to mlir/test, and
    Runtime tests should be added to runtime/tests.

When all the above are checked, delete everything above the dashed
line and fill in the pull request template.


Context:

Description of the Change:

Benefits:

Possible Drawbacks:

Related GitHub Issues:

The GPU half of gpu_verbs is hipMalloc plus
hipMemGetHandleForAddressRange(DmaBufFd), which hipcc maps onto
cuMemGetHandleForAddressRange. Whether a given NVIDIA GPU exports device
memory that way is a property of the device and driver, needs no RDMA
device to establish, and currently gates any plan for testing the GPU
RDMA path. The probe attempts the export directly rather than reading
CU_DEVICE_ATTRIBUTE_DMA_BUF_SUPPORTED, which is new in CUDA 13.0 and so
absent from the cu129 stack this job installs.

Runs only on workflow_dispatch; probe_only=true skips the build job so
the GPU host is held for seconds rather than the full build.
The A10G answered CUDA_ERROR_INVALID_VALUE for the page-locked host
allocation because the probe handed cuMemGetHandleForAddressRange the
device pointer from cuMemHostGetDevicePointer. The documented exportable
range for cuMemHostAlloc is the host pointer, so the error said nothing
about whether the device supports the export.
Catch2 exits 4 when a binary ran no tests, which is exactly what an
all-skipped suite looks like from outside: on a host with no RDMA device
the verbs suites skip every case. Under set -e that aborted the loop, so
the suites after it never ran and the job reported a test failure -- on a
device-less machine runner_tests_transport_memcpy was silently lost that
way. --allow-running-no-tests makes the skip exit 0 instead.

The same glob also matched the non-executable *_include.cmake and
*_tests.cmake files catch_discover_tests writes beside the binaries. Two
of the three loops had no -x guard and would have tried to execute them.

All three loops were copies of each other, so they now share one define.
The GPU coprocessor registers device memory with the NIC as a dma-buf --
hipMalloc, then hipMemGetHandleForAddressRange in GpuRuntime.hip, then
the MemoryRegion dma-buf constructor -- and nothing exercised that
constructor off a GPU host. udmabuf produces an equivalent fd from host
memory, so the registration branch is reachable with neither a GPU nor a
HIP toolchain.

Skips on three counts: no rxe0, no /dev/udmabuf, or a provider without
reg_user_mr_dmabuf. Soft-RoCE is the last of those on 6.8 (dma-buf
support for rxe was only submitted upstream in March 2026), so the case
skips today and turns into a real assertion once it runs against a
provider that implements it.
Test_TransportGpu.cpp is entirely STATIC_REQUIRE: the Payload frame
layout, the 64 B ring slot, the 16 B handoff slot, K_RING_SLOTS. None of
it needs a GPU at runtime, and neither GpuRuntime.hpp nor
GpuCoprocessorSession.hpp includes a HIP header -- hipStream_t is kept as
an opaque void* precisely so they stay includable.

Gating the whole target on TRANSPORT_HAS_HIP therefore confined these ABI
checks to GPU hosts, where a struct-reordering regression could have
merged from any transport PR. Only the library it links needs the gate.

transport_tests_all gated the dependency the same way, which is why the
target could configure while the binary never built.
gpu_verbs_selftest exercises the coprocessor session end to end -- RC
bring-up, MR and key exchange, the ring and handoff protocol, launcher
dispatch, collect, teardown -- but needed a GPU for two things only: the
allocations and the persistent kernel. TRANSPORT_GPU_STUB=ON supplies
both from the host, so the session is testable on any machine with an
RDMA device, and the selftest passes against a cpu_verbs controller over
rxe0.

GpuRuntimeHost.cpp implements the same GpuRuntime.hpp declarations from
64 B aligned host pages; one address space, so each mapping's device view
is the host pointer. GpuLaunchersHost.cpp mirrors fused<DECODE> step for
step in a host thread, with acquire/release fences where the kernel uses
__threadfence_system and the stop flag sampled on the same interval. Both
decoders reuse the constexpr tables in SteaneLut.hpp rather than
duplicating them.

alloc_memory has to register host pages, since they have no dma-buf
export. That is under #ifdef, not a runtime fallback: on real hardware
the export always yields an fd, and quietly registering host memory when
it did not would turn a failed GPUDirect setup into a slow wrong success.
The #else branch is unchanged, and HIP still wins wherever it is present.
The GPU backends are HIP sources that only ever get built by nvcc against
fetched hip-dev headers (lib/transport/CMakeLists.txt), so nothing checks
them against the compiler they are written for and an AMD-only error
would surface first on real AMD hardware. Device-only compilation needs
no GPU and no driver, so this runs on the GH-hosted x86_64 runners,
gated on the existing transport path filter. Both sources are clean for
gfx950 and gfx90a today.

Two things that cost time to find, recorded in the job and the script:

* The ROCm repo has to be pinned above Ubuntu universe. Otherwise apt
  satisfies the HIP dependencies with universe's libamdhip64-dev 5.7.1,
  whose /usr/include/hip headers shadow ROCm's and predate
  hipMemRangeHandleTypeDmaBufFd -- the build then fails on an enum that
  does exist in 7.1.1, at hip_runtime_api.h:2006.
* rocm-device-libs is a separate package from rocm-llvm and carries the
  amdgcn bitcode; without it amdclang++ refuses device compilation.

compile_check.sh runs amdclang++ directly when it is on PATH and
otherwise re-executes itself inside a container that has one, so CI and a
laptop run the same check. `make check-hip-amd` is the local entry point.
ROCm publishes x86_64 packages only, hence --platform linux/amd64 in the
container path.
rocm-ernic is AMD's libvfio-user RDMA NIC emulator. It builds and
self-tests on arm64 (3 of 5 ctest cases pass; the two data-path cases
need a VM by upstream's own account), and its guest driver implements
reg_user_mr_dmabuf -- the call Soft-RoCE answers EOPNOTSUPP to, and the
one the GPU coprocessor needs. That makes it the only dma-buf capable
provider reachable without hardware, which is the reason to keep this
around.

The README records what a real device costs from here: nested virt, a
QEMU with the vfio-user client (Debian sid packages 11.1.1 with it), the
guest driver and custom rdma-core, and a GPU passed through with
vfio-pci for the GPU path. Two upstream arm64 gaps are noted with it:
INSTALL.md omits libcmocka-dev, and rocm-ernic's find_library fallback
hints name x86_64-linux-gnu only.

The rocjitsu patch is separate: aarch64 has no dup2 syscall, so its KMD
interposer does not compile there. Worth sending upstream.
@multiphaseCFD
multiphaseCFD changed the base branch from main to shuli/add-transport-runtime-ci September 2, 2026 18:37
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.

1 participant