CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
114 lines
4.4 KiB
Python
114 lines
4.4 KiB
Python
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 Advanced Micro Devices, Inc. All rights reserved.
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
"""Interop / zero-copy tests for the RCCL fork.
|
|
|
|
Two tests, both marked ``mpi``:
|
|
|
|
* PyTorch-ROCm DLPack: ``torch.Tensor`` -> ``Communicator.reduce`` ->
|
|
assert ``data_ptr()`` is unchanged. Additionally verifies that the
|
|
DLPack capsule reports ``device_type == 10`` (kROCM), reusing the
|
|
kROCM helpers shipped with the cuda.core HIP shim.
|
|
* CuPy-ROCm CUDA Array Interface: ``cupy.ndarray`` ->
|
|
``Communicator.reduce`` -> assert ``arr.data.ptr`` is unchanged.
|
|
|
|
These cover the "zero-copy via pointer identity" guarantee; numerical
|
|
correctness of the underlying ``all_reduce`` is exercised by
|
|
``test_collectives.py``.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
torch = pytest.importorskip("torch", reason="torch-ROCm required for the DLPack test")
|
|
|
|
import nccl # noqa: E402 (also registers the cuda.core shim under sys.modules)
|
|
import nccl.core as nccl_core # noqa: E402
|
|
|
|
from conftest import require_at_least_n_ranks, xfail_if_fewer_than_8_gpus # noqa: E402
|
|
|
|
pytestmark = [
|
|
pytest.mark.mpi,
|
|
xfail_if_fewer_than_8_gpus(),
|
|
]
|
|
|
|
_N = 4096
|
|
|
|
|
|
def test_dlpack_zero_copy_pytorch(comm, rank_info, device):
|
|
"""PyTorch tensor: pointer identity preserved across an all_reduce, and
|
|
the DLPack capsule reports kROCM (device_type == 10)."""
|
|
require_at_least_n_ranks(rank_info, 2)
|
|
rank, _ = rank_info
|
|
|
|
t = torch.full((_N,), float(rank + 1), dtype=torch.float32, device=device)
|
|
ptr_before = int(t.data_ptr())
|
|
|
|
# In-place all_reduce: same buffer for send / recv.
|
|
comm.reduce(t, t, nccl_core.SUM)
|
|
torch.cuda.synchronize()
|
|
|
|
ptr_after = int(t.data_ptr())
|
|
assert (
|
|
ptr_after == ptr_before
|
|
), f"data_ptr mutated by all_reduce: before={ptr_before:#x} after={ptr_after:#x}"
|
|
|
|
# __dlpack_device__ is the cheap probe: it must report kROCM (10) on
|
|
# ROCm regardless of which producer (torch / cuda.core) created the
|
|
# capsule.
|
|
dl_dev = t.__dlpack_device__()
|
|
# PyTorch reports (DLDeviceType.ROCM=10, device_id) on a ROCm build.
|
|
assert int(dl_dev[0]) == 10, f"expected device_type=10 (kROCM), got {dl_dev}"
|
|
|
|
# Round-trip a capsule and re-parse it via the cuda.core shim's
|
|
# parser to confirm the wire format also says 10.
|
|
from nccl._hip_compat.cuda_core_shim._dlpack import parse_capsule
|
|
|
|
capsule = t.__dlpack__()
|
|
dl_tensor, _, _ = parse_capsule(capsule)
|
|
assert int(dl_tensor.device.device_type) == 10
|
|
|
|
|
|
def test_cai_zero_copy_cupy(comm, rank_info, device):
|
|
"""CuPy array: pointer identity preserved across an all_reduce.
|
|
|
|
The AC asks for ``cupy.ndarray`` consumed via the CUDA Array Interface,
|
|
not for CuPy as the source of the data. We therefore allocate the
|
|
storage with PyTorch (which does not need HIPRTC at runtime) and wrap
|
|
it with ``cupy.asarray``, which is the canonical CAI consumer path:
|
|
``cupy.asarray`` reads ``__cuda_array_interface__`` and constructs an
|
|
``ndarray`` that aliases the existing device pointer with no kernel
|
|
launch and no JIT compile. As a side effect this matches the AC's
|
|
"via pointer identity" wording exactly: ``int(arr.data.ptr)`` must
|
|
equal ``int(t.data_ptr())`` both before and after the collective.
|
|
|
|
Going through ``cupy.full`` / ``cupy.zeros`` instead would JIT-compile
|
|
a fill / copy kernel via HIPRTC, which fails on dev images that
|
|
don't ship the matching libstdc++ headers (HIPRTC's clang cannot
|
|
locate ``stddef.h``). That failure mode is unrelated to the binding
|
|
and out of scope for this test.
|
|
"""
|
|
require_at_least_n_ranks(rank_info, 2)
|
|
cupy = pytest.importorskip("cupy", reason="cupy-ROCm required for the CAI test")
|
|
|
|
rank, _ = rank_info
|
|
t = torch.full((_N,), float(rank + 1), dtype=torch.float32, device=device)
|
|
torch_ptr = int(t.data_ptr())
|
|
|
|
with cupy.cuda.Device(device.index):
|
|
arr = cupy.asarray(t)
|
|
ptr_before = int(arr.data.ptr)
|
|
assert ptr_before == torch_ptr, (
|
|
"cupy.asarray must alias the source CAI pointer (zero-copy): "
|
|
f"torch={torch_ptr:#x} cupy={ptr_before:#x}"
|
|
)
|
|
|
|
comm.reduce(arr, arr, nccl_core.SUM)
|
|
cupy.cuda.runtime.deviceSynchronize()
|
|
|
|
ptr_after = int(arr.data.ptr)
|
|
assert (
|
|
ptr_after == ptr_before
|
|
), f"cupy.data.ptr mutated by all_reduce: before={ptr_before:#x} after={ptr_after:#x}"
|