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
215 lines
6.8 KiB
C++
215 lines
6.8 KiB
C++
/*************************************************************************
|
|
* Copyright (c) 2026 Advanced Micro Devices, Inc. All rights reserved.
|
|
*
|
|
* See LICENSE.txt for license information
|
|
************************************************************************/
|
|
|
|
/**
|
|
* @file HostApiHelpers.hpp
|
|
* @brief Helper utilities for testing RCCL's one-sided RMA (Host API)
|
|
*
|
|
* Provides:
|
|
* - allocFineGrainBuffer / freeFineGrainBuffer via ncclMemAlloc / ncclMemFree
|
|
* - NcclWindowGuard: RAII wrapper for ncclCommWindowRegister / ncclCommWindowDeregister
|
|
* - fillPatternBytes / verifyPatternBytes for byte-level test patterns on CPU-accessible
|
|
* (fine-grain) memory
|
|
*
|
|
*/
|
|
|
|
#ifndef HOST_API_HELPERS_HPP
|
|
#define HOST_API_HELPERS_HPP
|
|
|
|
#ifdef MPI_TESTS_ENABLED
|
|
|
|
#include "rccl/rccl.h"
|
|
#include <hip/hip_runtime.h>
|
|
#include <cstdint>
|
|
#include <cstdio>
|
|
#include <cstring>
|
|
#include <vector>
|
|
|
|
namespace RCCLHostApiHelpers
|
|
{
|
|
|
|
// ============================================================================
|
|
// Fine-grain buffer allocation
|
|
// ============================================================================
|
|
|
|
/**
|
|
* @brief Allocate fine-grain (CPU-accessible) memory via ncclMemAlloc.
|
|
*
|
|
* On ROCm the returned pointer is host-accessible without hipMemcpy.
|
|
*
|
|
* @param ptr Out: receives allocated pointer.
|
|
* @param size Requested size in bytes.
|
|
* @return ncclResult_t from ncclMemAlloc.
|
|
*/
|
|
inline ncclResult_t allocFineGrainBuffer(void** ptr, size_t size)
|
|
{
|
|
return ncclMemAlloc(ptr, size);
|
|
}
|
|
|
|
/**
|
|
* @brief Free fine-grain memory previously allocated with allocFineGrainBuffer.
|
|
*
|
|
* @param ptr Pointer to free (no-op if nullptr).
|
|
* @return ncclResult_t from ncclMemFree, or ncclSuccess if ptr was nullptr.
|
|
*/
|
|
inline ncclResult_t freeFineGrainBuffer(void* ptr)
|
|
{
|
|
if(!ptr)
|
|
return ncclSuccess;
|
|
return ncclMemFree(ptr);
|
|
}
|
|
|
|
// ============================================================================
|
|
// RAII guard for ncclWindow_t
|
|
// ============================================================================
|
|
|
|
/**
|
|
* @struct NcclWindowGuard
|
|
* @brief RAII wrapper for ncclCommWindowRegister / ncclCommWindowDeregister.
|
|
*
|
|
* Constructor calls ncclCommWindowRegister. Destructor calls
|
|
* ncclCommWindowDeregister only if win_ is non-null.
|
|
*
|
|
* Usage:
|
|
* @code
|
|
* void* buf = nullptr;
|
|
* allocFineGrainBuffer(&buf, kSize);
|
|
* ncclWindow_t win = nullptr;
|
|
* NcclWindowGuard wg(comm, buf, kSize, &win, NCCL_WIN_DEFAULT);
|
|
* if (win == nullptr) { GTEST_SKIP() << "Windows not supported"; }
|
|
* // ... use win ...
|
|
* // Destructor calls ncclCommWindowDeregister automatically.
|
|
* @endcode
|
|
*/
|
|
struct NcclWindowGuard
|
|
{
|
|
ncclComm_t comm_ = nullptr;
|
|
ncclWindow_t win_ = nullptr;
|
|
ncclResult_t initResult_ = ncclSuccess;
|
|
|
|
NcclWindowGuard() = default;
|
|
|
|
/**
|
|
* @brief Register a memory window.
|
|
*
|
|
* @param comm RCCL communicator (collective across all ranks).
|
|
* @param buff Buffer to register (fine-grain, CPU-accessible).
|
|
* @param size Size of the buffer in bytes.
|
|
* @param winOut Out: receives the window handle.
|
|
* @param winFlags Window flags (use NCCL_WIN_DEFAULT = 0x00 for proxy GIN path).
|
|
*/
|
|
NcclWindowGuard(ncclComm_t comm,
|
|
void* buff,
|
|
size_t size,
|
|
ncclWindow_t* winOut,
|
|
int winFlags)
|
|
: comm_(comm)
|
|
{
|
|
initResult_ = ncclCommWindowRegister(comm_, buff, size, &win_, winFlags);
|
|
if(winOut)
|
|
*winOut = win_;
|
|
}
|
|
|
|
~NcclWindowGuard()
|
|
{
|
|
if(win_ && comm_)
|
|
{
|
|
ncclResult_t res = ncclCommWindowDeregister(comm_, win_);
|
|
if(res != ncclSuccess)
|
|
{
|
|
fprintf(stderr,
|
|
"WARNING: ncclCommWindowDeregister failed in destructor: %s\n",
|
|
ncclGetErrorString(res));
|
|
}
|
|
win_ = nullptr;
|
|
}
|
|
}
|
|
|
|
// Non-copyable, non-movable (owns the handle)
|
|
NcclWindowGuard(const NcclWindowGuard&) = delete;
|
|
NcclWindowGuard& operator=(const NcclWindowGuard&) = delete;
|
|
NcclWindowGuard(NcclWindowGuard&&) = delete;
|
|
NcclWindowGuard& operator=(NcclWindowGuard&&) = delete;
|
|
|
|
ncclResult_t initResult() const { return initResult_; }
|
|
ncclWindow_t win() const { return win_; }
|
|
bool valid() const { return win_ != nullptr; }
|
|
};
|
|
|
|
// ============================================================================
|
|
// Pattern fill / verify (hipMemcpy staging — works on device and fine-grain)
|
|
// ============================================================================
|
|
|
|
/** Fill buf with pattern (seed + i) % 256 via hipMemcpy staging. */
|
|
inline void FillBuf(void* buf, size_t size, int seed)
|
|
{
|
|
std::vector<uint8_t> tmp(size);
|
|
for(size_t i = 0; i < size; ++i)
|
|
tmp[i] = static_cast<uint8_t>((seed + i) % 256);
|
|
ASSERT_EQ(hipMemcpy(buf, tmp.data(), size, hipMemcpyHostToDevice), hipSuccess);
|
|
ASSERT_EQ(hipDeviceSynchronize(), hipSuccess);
|
|
}
|
|
|
|
/** Return true iff buf matches (seed + i) % 256 for all i. */
|
|
inline bool VerifyBuf(const void* buf, size_t size, int seed)
|
|
{
|
|
std::vector<uint8_t> staging(size);
|
|
if(hipMemcpy(staging.data(), buf, size, hipMemcpyDeviceToHost) != hipSuccess)
|
|
return false;
|
|
if (hipDeviceSynchronize() != hipSuccess)
|
|
return false;
|
|
for(size_t i = 0; i < size; ++i)
|
|
{
|
|
if(staging[i] != static_cast<uint8_t>((seed + i) % 256))
|
|
{
|
|
fprintf(stderr,
|
|
"VerifyBuf: mismatch at byte %zu: expected %u got %u (seed=%d)\n",
|
|
i,
|
|
static_cast<unsigned>((seed + i) % 256),
|
|
static_cast<unsigned>(staging[i]),
|
|
seed);
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/** Fill buf with a constant sentinel byte via hipMemset. */
|
|
inline void FillSentinel(void* buf, size_t size, uint8_t value)
|
|
{
|
|
ASSERT_EQ(hipMemset(buf, value, size), hipSuccess);
|
|
ASSERT_EQ(hipDeviceSynchronize(), hipSuccess);
|
|
}
|
|
|
|
/** Return true iff every byte in buf equals value. */
|
|
inline bool AllSentinel(const void* buf, size_t size, uint8_t value)
|
|
{
|
|
std::vector<uint8_t> staging(size);
|
|
if(hipMemcpy(staging.data(), buf, size, hipMemcpyDeviceToHost) != hipSuccess)
|
|
return false;
|
|
if (hipDeviceSynchronize() != hipSuccess)
|
|
return false;
|
|
for(size_t i = 0; i < size; ++i)
|
|
{
|
|
if(staging[i] != value)
|
|
{
|
|
fprintf(stderr,
|
|
"AllSentinel: mismatch at byte %zu: expected 0x%02x got 0x%02x\n",
|
|
i,
|
|
static_cast<unsigned>(value),
|
|
static_cast<unsigned>(staging[i]));
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
} // namespace RCCLHostApiHelpers
|
|
|
|
#endif // MPI_TESTS_ENABLED
|
|
|
|
#endif // HOST_API_HELPERS_HPP
|