Files
TheRock/rocm-systems/projects/rccl/bindings/nccl4py/tests/test_interop.py
T
derek.holloway 7502bf64a4
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
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

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}"