Merge commit '3d4813d99196bb349eccd50a925e2addc8f1622c' into develop
Este cometimento está contido em:
@@ -10,12 +10,12 @@
|
||||
|
||||
namespace RcclUnitTesting
|
||||
{
|
||||
TEST(AllToAll, OutOfPlace)
|
||||
TEST(AlltoAll, OutOfPlace)
|
||||
{
|
||||
TestBed testBed;
|
||||
|
||||
// Configuration
|
||||
std::vector<ncclFunc_t> const funcTypes = {ncclCollAllToAll};
|
||||
std::vector<ncclFunc_t> const funcTypes = {ncclCollAlltoAll};
|
||||
std::vector<ncclDataType_t> const dataTypes = {ncclFloat16, ncclFloat32};
|
||||
std::vector<ncclRedOp_t> const redOps = {ncclSum};
|
||||
std::vector<int> const roots = {0};
|
||||
@@ -29,12 +29,12 @@ namespace RcclUnitTesting
|
||||
testBed.Finalize();
|
||||
}
|
||||
|
||||
TEST(AllToAll, OutOfPlaceGraph)
|
||||
TEST(AlltoAll, OutOfPlaceGraph)
|
||||
{
|
||||
TestBed testBed;
|
||||
|
||||
// Configuration
|
||||
std::vector<ncclFunc_t> const funcTypes = {ncclCollAllToAll};
|
||||
std::vector<ncclFunc_t> const funcTypes = {ncclCollAlltoAll};
|
||||
std::vector<ncclDataType_t> const dataTypes = {ncclFloat64, ncclBfloat16, ncclFloat8e4m3, ncclFloat8e5m2};
|
||||
std::vector<ncclRedOp_t> const redOps = {ncclSum};
|
||||
std::vector<int> const roots = {0};
|
||||
@@ -48,12 +48,12 @@ namespace RcclUnitTesting
|
||||
testBed.Finalize();
|
||||
}
|
||||
|
||||
TEST(AllToAll, ManagedMem)
|
||||
TEST(AlltoAll, ManagedMem)
|
||||
{
|
||||
TestBed testBed;
|
||||
|
||||
// Configuration
|
||||
std::vector<ncclFunc_t> const funcTypes = {ncclCollAllToAll};
|
||||
std::vector<ncclFunc_t> const funcTypes = {ncclCollAlltoAll};
|
||||
std::vector<ncclDataType_t> const dataTypes = {ncclUint8};
|
||||
std::vector<ncclRedOp_t> const redOps = {ncclSum};
|
||||
std::vector<int> const roots = {0};
|
||||
@@ -67,12 +67,12 @@ namespace RcclUnitTesting
|
||||
testBed.Finalize();
|
||||
}
|
||||
|
||||
TEST(AllToAll, ManagedMemGraph)
|
||||
TEST(AlltoAll, ManagedMemGraph)
|
||||
{
|
||||
TestBed testBed;
|
||||
|
||||
// Configuration
|
||||
std::vector<ncclFunc_t> const funcTypes = {ncclCollAllToAll};
|
||||
std::vector<ncclFunc_t> const funcTypes = {ncclCollAlltoAll};
|
||||
std::vector<ncclDataType_t> const dataTypes = {ncclUint32, ncclUint64};
|
||||
std::vector<ncclRedOp_t> const redOps = {ncclSum};
|
||||
std::vector<int> const roots = {0};
|
||||
@@ -86,13 +86,13 @@ namespace RcclUnitTesting
|
||||
testBed.Finalize();
|
||||
}
|
||||
|
||||
TEST(AllToAll, Channels)
|
||||
TEST(AlltoAll, Channels)
|
||||
{
|
||||
TestBed testBed;
|
||||
if(testBed.ev.maxGpus >= 8) {
|
||||
if(testBed.ev.isGfx94) {
|
||||
// Configuration
|
||||
std::vector<ncclFunc_t> const funcTypes = {ncclCollAllToAll};
|
||||
std::vector<ncclFunc_t> const funcTypes = {ncclCollAlltoAll};
|
||||
std::vector<ncclDataType_t> const dataTypes = {ncclBfloat16};
|
||||
std::vector<ncclRedOp_t> const redOps = {ncclSum};
|
||||
std::vector<int> const roots = {0};
|
||||
|
||||
@@ -74,7 +74,7 @@ namespace RcclUnitTesting
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AllToAllv, OutOfPlace)
|
||||
TEST(AlltoAllv, OutOfPlace)
|
||||
{
|
||||
TestBed testBed;
|
||||
|
||||
@@ -100,7 +100,7 @@ namespace RcclUnitTesting
|
||||
const std::vector<int>& gpuPriorityOrder = testBed.ev.GetGpuPriorityOrder();
|
||||
testBed.InitComms(TestBed::GetDeviceIdsList(numProcesses, totalRanks, gpuPriorityOrder));
|
||||
|
||||
// Prepare AllToAllV options
|
||||
// Prepare AlltoAllV options
|
||||
std::vector<size_t> numInputElements;
|
||||
std::vector<size_t> numOutputElements;
|
||||
PrepareCounts(totalRanks, 256, options, numInputElements, numOutputElements, 40);
|
||||
@@ -110,14 +110,14 @@ namespace RcclUnitTesting
|
||||
if (testBed.ev.showNames)
|
||||
{
|
||||
std::string name = testBed.GetTestCaseName(totalRanks, isMultiProcess,
|
||||
ncclCollAllToAllv, dataTypes[dataIdx],
|
||||
ncclCollAlltoAllv, dataTypes[dataIdx],
|
||||
ncclSum, -1, inPlace, useManagedMem, useHipGraph);
|
||||
INFO("%s\n", name.c_str());
|
||||
}
|
||||
|
||||
for (int rank = 0; rank < totalRanks; ++rank)
|
||||
{
|
||||
testBed.SetCollectiveArgs(ncclCollAllToAllv,
|
||||
testBed.SetCollectiveArgs(ncclCollAlltoAllv,
|
||||
dataTypes[dataIdx],
|
||||
numInputElements[rank],
|
||||
numOutputElements[rank],
|
||||
@@ -138,7 +138,7 @@ namespace RcclUnitTesting
|
||||
}
|
||||
|
||||
|
||||
TEST(AllToAllv, OutOfPlaceGraph)
|
||||
TEST(AlltoAllv, OutOfPlaceGraph)
|
||||
{
|
||||
TestBed testBed;
|
||||
|
||||
@@ -164,7 +164,7 @@ namespace RcclUnitTesting
|
||||
const std::vector<int>& gpuPriorityOrder = testBed.ev.GetGpuPriorityOrder();
|
||||
testBed.InitComms(TestBed::GetDeviceIdsList(numProcesses, totalRanks, gpuPriorityOrder));
|
||||
|
||||
// Prepare AllToAllV options
|
||||
// Prepare AlltoAllV options
|
||||
std::vector<size_t> numInputElements;
|
||||
std::vector<size_t> numOutputElements;
|
||||
PrepareCounts(totalRanks, 256, options, numInputElements, numOutputElements, 60);
|
||||
@@ -174,14 +174,14 @@ namespace RcclUnitTesting
|
||||
if (testBed.ev.showNames)
|
||||
{
|
||||
std::string name = testBed.GetTestCaseName(totalRanks, isMultiProcess,
|
||||
ncclCollAllToAllv, dataTypes[dataIdx],
|
||||
ncclCollAlltoAllv, dataTypes[dataIdx],
|
||||
ncclSum, -1, inPlace, useManagedMem, useHipGraph);
|
||||
INFO("%s\n", name.c_str());
|
||||
}
|
||||
|
||||
for (int rank = 0; rank < totalRanks; ++rank)
|
||||
{
|
||||
testBed.SetCollectiveArgs(ncclCollAllToAllv,
|
||||
testBed.SetCollectiveArgs(ncclCollAlltoAllv,
|
||||
dataTypes[dataIdx],
|
||||
numInputElements[rank],
|
||||
numOutputElements[rank],
|
||||
|
||||
A apresentação das diferenças no ficheiro foi suprimida por ser demasiado grande
Carregar diff
@@ -153,6 +153,7 @@ if(BUILD_TESTS)
|
||||
NonBlockingTests.cpp
|
||||
ReduceScatterTests.cpp
|
||||
ReduceTests.cpp
|
||||
RegisterTests.cpp
|
||||
ScatterTests.cpp
|
||||
SendRecvTests.cpp
|
||||
StandaloneTests.cpp
|
||||
@@ -163,6 +164,7 @@ if(BUILD_TESTS)
|
||||
common/EnvVars.cpp
|
||||
common/PrepDataFuncs.cpp
|
||||
common/PtrUnion.cpp
|
||||
common/ProcessIsolatedTestRunner.cpp
|
||||
common/TestBed.cpp
|
||||
common/TestBedChild.cpp
|
||||
common/StandaloneUtils.cpp
|
||||
@@ -236,6 +238,25 @@ if(BUILD_TESTS)
|
||||
list(APPEND RCCL_TEST_EXECUTABLES rccl-UnitTestsMPI)
|
||||
|
||||
endif()
|
||||
|
||||
# rccl-UnitTestsAltRsmi: Uses TEST BUILD alt_rsmi.cc (ARSMI_TEST_BUILD)
|
||||
# This separate executable compiles alt_rsmi.cc with ARSMI_TEST_BUILD,
|
||||
# enabling external linkage of internal variables so that
|
||||
# tests can access and manipulate them for testing.
|
||||
list(APPEND RCCL_TEST_EXECUTABLES rccl-UnitTestsAltRsmi)
|
||||
|
||||
set(TEST_ALTRSMI_SOURCE_FILES
|
||||
AltRsmiTests.cpp
|
||||
../src/misc/alt_rsmi.cc
|
||||
common/main_fixtures.cpp
|
||||
common/EnvVars.cpp
|
||||
common/ProcessIsolatedTestRunner.cpp
|
||||
)
|
||||
|
||||
add_executable(rccl-UnitTestsAltRsmi ${TEST_ALTRSMI_SOURCE_FILES})
|
||||
|
||||
# Define ARSMI_TEST_BUILD specifically for rccl-UnitTestsAltRsmi
|
||||
target_compile_definitions(rccl-UnitTestsAltRsmi PRIVATE ARSMI_TEST_BUILD)
|
||||
endif()
|
||||
|
||||
foreach(test_executable IN LISTS RCCL_TEST_EXECUTABLES)
|
||||
|
||||
@@ -81,7 +81,7 @@ namespace RcclUnitTesting
|
||||
ncclCollAllReduce,
|
||||
ncclCollGather,
|
||||
ncclCollScatter,
|
||||
ncclCollAllToAll};
|
||||
ncclCollAlltoAll};
|
||||
int const numCollPerGroup = funcTypes.size();
|
||||
int const numElements = 1048576;
|
||||
bool const inPlace = false;
|
||||
@@ -251,7 +251,7 @@ namespace RcclUnitTesting
|
||||
|
||||
// Configuration
|
||||
std::vector<std::vector<ncclFunc_t>> const groupCalls = {{ncclCollAllReduce, ncclCollAllGather},
|
||||
{ncclCollAllToAll, ncclCollGather},
|
||||
{ncclCollAlltoAll, ncclCollGather},
|
||||
{ncclCollBroadcast, ncclCollReduceScatter}};
|
||||
std::vector<std::vector<int>> const numElements = {{1250, 1048576}, {384, 384 * 1024}, {1048576, 127}};
|
||||
std::vector<ncclDataType_t> const testDataTypes = {ncclFloat16, ncclFloat32, ncclBfloat16};
|
||||
|
||||
@@ -143,7 +143,12 @@ private:
|
||||
|
||||
protected:
|
||||
void SetUp() override {
|
||||
ncclResult_t result = ncclNetSocket.init(nullptr, nullptr);
|
||||
void* ctx = nullptr;
|
||||
uint64_t commId = 0;
|
||||
ncclNetCommConfig_t config = {};
|
||||
ncclDebugLogger_t logFunction = nullptr;
|
||||
ncclProfilerCallback_t profFunction = nullptr;
|
||||
ncclResult_t result = ncclNetSocket.init(&ctx, commId, &config, logFunction, profFunction);
|
||||
ASSERT_EQ(result, ncclSuccess) << "Failed to initialize ncclNetSocket. "
|
||||
<< "Error code: " << result
|
||||
<< ". Ensure RCCL networking is properly configured.";
|
||||
@@ -256,8 +261,9 @@ protected:
|
||||
|
||||
// Increased attempts and longer total timeout for reliability
|
||||
for (int attempt = 0; attempt < 100 && !shouldStop.load(); attempt++) {
|
||||
ncclResult_t connectResult = ncclNetSocket.connect(
|
||||
0, &config, handle, &tempSendComm, &sendDevComm);
|
||||
void* ctx = nullptr;
|
||||
int dev = 0;
|
||||
ncclResult_t connectResult = ncclNetSocket.connect(ctx, dev, handle, &tempSendComm, &sendDevComm);
|
||||
if (connectResult == ncclSuccess && tempSendComm != nullptr) {
|
||||
sendGuard.reset(tempSendComm);
|
||||
connectCompleted = true;
|
||||
@@ -702,7 +708,7 @@ protected:
|
||||
char handle[NCCL_NET_HANDLE_MAXSIZE];
|
||||
void *listenComm = nullptr;
|
||||
|
||||
ncclResult_t result = ncclNetSocket.listen(0, handle, &listenComm);
|
||||
ncclResult_t result = ncclNetSocket.listen(nullptr, 0, handle, &listenComm);
|
||||
ASSERT_EQ(result, ncclSuccess) << "Failed to establish listening socket for test execution. "
|
||||
<< "ncclNetSocket.listen() returned error code: " << result
|
||||
<< ". Verify network device availability and port accessibility.";
|
||||
@@ -791,7 +797,9 @@ TEST_F(NetSocketTests, TestConcurrentOperationsTaskCreationDefault) {
|
||||
char handle[NCCL_NET_HANDLE_MAXSIZE];
|
||||
void *listenComm = nullptr;
|
||||
|
||||
ncclResult_t result = ncclNetSocket.listen(0, handle, &listenComm);
|
||||
void* ctx = nullptr;
|
||||
int dev = 0;
|
||||
ncclResult_t result = ncclNetSocket.listen(ctx, dev, handle, &listenComm);
|
||||
ASSERT_EQ(result, ncclSuccess) << "Failed to establish listening socket for test execution. "
|
||||
<< "ncclNetSocket.listen() returned error code: " << result
|
||||
<< ". Verify network device availability and port accessibility.";
|
||||
@@ -895,7 +903,9 @@ TEST_F(NetSocketTests, TestInvalidDeviceIndexListen) {
|
||||
void *listenComm = nullptr;
|
||||
|
||||
// Test with negative device index
|
||||
ncclResult_t result = ncclNetSocket.listen(-1, handle, &listenComm);
|
||||
void* ctx = nullptr;
|
||||
int dev = -1;
|
||||
ncclResult_t result = ncclNetSocket.listen(ctx, dev, handle, &listenComm);
|
||||
INFO(NCCL_LOG_INFO, "Listen with dev=-1 returned: %d", result);
|
||||
EXPECT_EQ(result, ncclInternalError)
|
||||
<< "Listen should fail with negative device index. "
|
||||
@@ -904,7 +914,7 @@ TEST_F(NetSocketTests, TestInvalidDeviceIndexListen) {
|
||||
|
||||
// Test with device index greater than available devices
|
||||
int invalidDev = ndev + 10;
|
||||
result = ncclNetSocket.listen(invalidDev, handle, &listenComm);
|
||||
result = ncclNetSocket.listen(ctx, invalidDev, handle, &listenComm);
|
||||
INFO(NCCL_LOG_INFO, "Listen with dev=%d (> ndev=%d) returned: %d", invalidDev,
|
||||
ndev, result);
|
||||
EXPECT_EQ(result, ncclInternalError)
|
||||
@@ -926,8 +936,9 @@ TEST_F(NetSocketTests, TestInvalidDeviceIndexConnect) {
|
||||
ncclNetDeviceHandle_t *sendDevComm = nullptr;
|
||||
|
||||
// Test with negative device index
|
||||
ncclResult_t result =
|
||||
ncclNetSocket.connect(-1, &config, handle, &sendComm, &sendDevComm);
|
||||
void* ctx = nullptr;
|
||||
int dev = -1;
|
||||
ncclResult_t result = ncclNetSocket.connect(ctx, dev, handle, &sendComm, &sendDevComm);
|
||||
INFO(NCCL_LOG_INFO, "Connect with dev=-1 returned: %d", result);
|
||||
EXPECT_EQ(result, ncclInternalError)
|
||||
<< "Connect should fail with negative device index. "
|
||||
@@ -936,8 +947,7 @@ TEST_F(NetSocketTests, TestInvalidDeviceIndexConnect) {
|
||||
|
||||
// Test with device index greater than available devices
|
||||
int invalidDev = ndev + 10;
|
||||
result = ncclNetSocket.connect(invalidDev, &config, handle, &sendComm,
|
||||
&sendDevComm);
|
||||
result = ncclNetSocket.connect(ctx, invalidDev, handle, &sendComm, &sendDevComm);
|
||||
INFO(NCCL_LOG_INFO, "Connect with dev=%d (> ndev=%d) returned: %d",
|
||||
invalidDev, ndev, result);
|
||||
EXPECT_EQ(result, ncclInternalError)
|
||||
@@ -973,7 +983,7 @@ TEST_F(NetSocketTests, TestInvalidArraySizeIrecv) {
|
||||
// Setup a dummy communicator first
|
||||
char handle[NCCL_NET_HANDLE_MAXSIZE];
|
||||
void *listenComm = nullptr;
|
||||
ncclResult_t result = ncclNetSocket.listen(0, handle, &listenComm);
|
||||
ncclResult_t result = ncclNetSocket.listen(nullptr, 0, handle, &listenComm);
|
||||
|
||||
if (result == ncclSuccess && listenComm) {
|
||||
void *sendComm = nullptr;
|
||||
@@ -1039,7 +1049,7 @@ TEST_F(NetSocketTests, TestNonHostMemoryRegMr) {
|
||||
// Setup a dummy communicator first
|
||||
char handle[NCCL_NET_HANDLE_MAXSIZE];
|
||||
void *listenComm = nullptr;
|
||||
ncclResult_t result = ncclNetSocket.listen(0, handle, &listenComm);
|
||||
ncclResult_t result = ncclNetSocket.listen(nullptr, 0, handle, &listenComm);
|
||||
|
||||
if (result == ncclSuccess && listenComm) {
|
||||
void *sendComm = nullptr;
|
||||
@@ -1189,7 +1199,7 @@ TEST_F(NetSocketTests, TestExcessiveThreadConfig) {
|
||||
// Initialize to trigger the warning logic
|
||||
char handle[NCCL_NET_HANDLE_MAXSIZE];
|
||||
void *listenComm = nullptr;
|
||||
ncclResult_t result = ncclNetSocket.listen(0, handle, &listenComm);
|
||||
ncclResult_t result = ncclNetSocket.listen(nullptr, 0, handle, &listenComm);
|
||||
|
||||
if (result == ncclSuccess && listenComm) {
|
||||
// The implementation should have limited the threads to
|
||||
@@ -1308,7 +1318,7 @@ TEST_F(NetSocketTests, TestExcessiveSocketConfig) {
|
||||
// Initialize to trigger the warning logic
|
||||
char handle[NCCL_NET_HANDLE_MAXSIZE];
|
||||
void *listenComm = nullptr;
|
||||
ncclResult_t result = ncclNetSocket.listen(0, handle, &listenComm);
|
||||
ncclResult_t result = ncclNetSocket.listen(nullptr, 0, handle, &listenComm);
|
||||
|
||||
if (result == ncclSuccess && listenComm) {
|
||||
// The implementation should have limited the sockets to
|
||||
@@ -1337,7 +1347,7 @@ TEST_F(NetSocketTests, TestRequestAllocationFailure) {
|
||||
// Setup communication
|
||||
char handle[NCCL_NET_HANDLE_MAXSIZE];
|
||||
void *listenComm = nullptr;
|
||||
ncclResult_t result = ncclNetSocket.listen(0, handle, &listenComm);
|
||||
ncclResult_t result = ncclNetSocket.listen(nullptr, 0, handle, &listenComm);
|
||||
|
||||
if (result == ncclSuccess && listenComm) {
|
||||
void *sendComm = nullptr;
|
||||
@@ -1441,7 +1451,7 @@ TEST_F(NetSocketTests, TestMessageSizeMismatch) {
|
||||
|
||||
char handle[NCCL_NET_HANDLE_MAXSIZE];
|
||||
void *listenComm = nullptr;
|
||||
ncclResult_t result = ncclNetSocket.listen(0, handle, &listenComm);
|
||||
ncclResult_t result = ncclNetSocket.listen(nullptr, 0, handle, &listenComm);
|
||||
|
||||
if (result == ncclSuccess && listenComm) {
|
||||
void *sendComm = nullptr;
|
||||
|
||||
@@ -0,0 +1,247 @@
|
||||
/*************************************************************************
|
||||
* Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved.
|
||||
*
|
||||
* See LICENSE.txt for license information
|
||||
************************************************************************/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <rccl/rccl.h>
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
|
||||
#include "common/ErrCode.hpp"
|
||||
#include "common/ProcessIsolatedTestRunner.hpp"
|
||||
#include "StandaloneUtils.hpp"
|
||||
|
||||
namespace RcclUnitTesting
|
||||
{
|
||||
|
||||
// Helper to check GPU availability
|
||||
static bool hasGpuAvailable() {
|
||||
int numDevices = 0;
|
||||
hipError_t err = hipGetDeviceCount(&numDevices);
|
||||
return (err == hipSuccess && numDevices >= 1);
|
||||
}
|
||||
|
||||
// Macro to skip test if no GPU is available
|
||||
#define SKIP_IF_NO_GPU() \
|
||||
do { \
|
||||
if (!hasGpuAvailable()) { \
|
||||
GTEST_SKIP() << "This test requires at least 1 GPU device."; \
|
||||
return; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
// Helper to initialize a single-rank communicator
|
||||
static ncclResult_t initSingleRankComm(ncclComm_t* comm) {
|
||||
ncclUniqueId id;
|
||||
ncclResult_t res = ncclGetUniqueId(&id);
|
||||
if (res != ncclSuccess) return res;
|
||||
return ncclCommInitRank(comm, 1, id, 0);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// Test implementation functions - parameterized by registration expectation
|
||||
//==============================================================================
|
||||
|
||||
/**
|
||||
* @brief Test basic register/deregister of a single buffer
|
||||
* @param expectNonNull If true, expect non-NULL handle (registration enabled)
|
||||
*/
|
||||
static void testCommRegisterDeregister(bool expectNonNull) {
|
||||
SKIP_IF_NO_GPU();
|
||||
|
||||
HIPCALL(hipSetDevice(0));
|
||||
|
||||
ncclComm_t comm;
|
||||
NCCLCHECK(initSingleRankComm(&comm));
|
||||
|
||||
// Create buffer on device
|
||||
const size_t bufferSize = 1024 * 1024; // 1 MB
|
||||
void* deviceBuffer = nullptr;
|
||||
HIPCALL(hipMalloc(&deviceBuffer, bufferSize));
|
||||
ASSERT_NE(deviceBuffer, nullptr) << "Failed to allocate device buffer";
|
||||
|
||||
// Register buffer with ncclCommRegister
|
||||
void* regHandle = nullptr;
|
||||
NCCLCHECK(ncclCommRegister(comm, deviceBuffer, bufferSize, ®Handle));
|
||||
|
||||
// Verify handle based on expected behavior
|
||||
if (expectNonNull) {
|
||||
EXPECT_NE(regHandle, nullptr)
|
||||
<< "Buffer registration failed: regHandle is NULL even though NCCL_LOCAL_REGISTER=1";
|
||||
} else {
|
||||
EXPECT_EQ(regHandle, nullptr)
|
||||
<< "Expected NULL handle when NCCL_LOCAL_REGISTER is disabled";
|
||||
}
|
||||
|
||||
// Deregister and clean up
|
||||
NCCLCHECK(ncclCommDeregister(comm, regHandle));
|
||||
HIPCALL(hipFree(deviceBuffer));
|
||||
NCCLCHECK(ncclCommDestroy(comm));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test registering multiple buffers simultaneously
|
||||
* @param expectNonNull If true, expect non-NULL handles and verify uniqueness
|
||||
*/
|
||||
static void testMultipleBufferRegistration(bool expectNonNull) {
|
||||
SKIP_IF_NO_GPU();
|
||||
|
||||
HIPCALL(hipSetDevice(0));
|
||||
|
||||
ncclComm_t comm;
|
||||
NCCLCHECK(initSingleRankComm(&comm));
|
||||
|
||||
// Create and register multiple buffers
|
||||
const int numBuffers = 4;
|
||||
const size_t bufferSize = 64 * 1024; // 64 KB each
|
||||
void* deviceBuffers[numBuffers] = {nullptr};
|
||||
void* regHandles[numBuffers] = {nullptr};
|
||||
|
||||
for (int i = 0; i < numBuffers; i++) {
|
||||
HIPCALL(hipMalloc(&deviceBuffers[i], bufferSize));
|
||||
ASSERT_NE(deviceBuffers[i], nullptr) << "Failed to allocate buffer " << i;
|
||||
|
||||
NCCLCHECK(ncclCommRegister(comm, deviceBuffers[i], bufferSize, ®Handles[i]));
|
||||
|
||||
if (expectNonNull) {
|
||||
EXPECT_NE(regHandles[i], nullptr) << "Registration failed for buffer " << i;
|
||||
} else {
|
||||
EXPECT_EQ(regHandles[i], nullptr) << "Expected NULL handle for buffer " << i;
|
||||
}
|
||||
}
|
||||
|
||||
// Verify all handles are unique (only when registration is enabled)
|
||||
if (expectNonNull) {
|
||||
for (int i = 0; i < numBuffers; i++) {
|
||||
for (int j = i + 1; j < numBuffers; j++) {
|
||||
if (regHandles[i] != nullptr && regHandles[j] != nullptr) {
|
||||
EXPECT_NE(regHandles[i], regHandles[j])
|
||||
<< "Buffers " << i << " and " << j << " have the same registration handle";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Deregister and clean up
|
||||
for (int i = 0; i < numBuffers; i++) {
|
||||
NCCLCHECK(ncclCommDeregister(comm, regHandles[i]));
|
||||
HIPCALL(hipFree(deviceBuffers[i]));
|
||||
}
|
||||
NCCLCHECK(ncclCommDestroy(comm));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test registering buffers of various sizes
|
||||
* @param expectNonNull If true, expect non-NULL handles for all sizes
|
||||
*/
|
||||
static void testVariableSizeBuffers(bool expectNonNull) {
|
||||
SKIP_IF_NO_GPU();
|
||||
|
||||
HIPCALL(hipSetDevice(0));
|
||||
|
||||
ncclComm_t comm;
|
||||
NCCLCHECK(initSingleRankComm(&comm));
|
||||
|
||||
// Test various buffer sizes: 4KB, 64KB, 1MB, 4MB
|
||||
const size_t sizes[] = {4096, 64 * 1024, 1024 * 1024, 4 * 1024 * 1024};
|
||||
const int numSizes = sizeof(sizes) / sizeof(sizes[0]);
|
||||
|
||||
for (int i = 0; i < numSizes; i++) {
|
||||
void* deviceBuffer = nullptr;
|
||||
void* regHandle = nullptr;
|
||||
|
||||
HIPCALL(hipMalloc(&deviceBuffer, sizes[i]));
|
||||
ASSERT_NE(deviceBuffer, nullptr) << "Failed to allocate buffer of size " << sizes[i];
|
||||
|
||||
NCCLCHECK(ncclCommRegister(comm, deviceBuffer, sizes[i], ®Handle));
|
||||
|
||||
if (expectNonNull) {
|
||||
EXPECT_NE(regHandle, nullptr)
|
||||
<< "Registration failed for buffer size " << sizes[i] << " bytes";
|
||||
} else {
|
||||
EXPECT_EQ(regHandle, nullptr)
|
||||
<< "Expected NULL handle for buffer size " << sizes[i] << " bytes";
|
||||
}
|
||||
|
||||
NCCLCHECK(ncclCommDeregister(comm, regHandle));
|
||||
HIPCALL(hipFree(deviceBuffer));
|
||||
}
|
||||
|
||||
NCCLCHECK(ncclCommDestroy(comm));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test deregistering NULL handle (should succeed as no-op)
|
||||
*/
|
||||
static void testDeregisterNullHandle() {
|
||||
SKIP_IF_NO_GPU();
|
||||
|
||||
HIPCALL(hipSetDevice(0));
|
||||
|
||||
ncclComm_t comm;
|
||||
NCCLCHECK(initSingleRankComm(&comm));
|
||||
|
||||
// Deregister NULL handle - should be a no-op
|
||||
NCCLCHECK(ncclCommDeregister(comm, nullptr));
|
||||
|
||||
NCCLCHECK(ncclCommDestroy(comm));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// Test configuration helpers
|
||||
//==============================================================================
|
||||
|
||||
// Environment configuration for disabled registration (default)
|
||||
static ProcessIsolatedTestRunner::TestConfig
|
||||
makeDisabledConfig(const std::string& name, std::function<void()> testFn) {
|
||||
return ProcessIsolatedTestRunner::TestConfig(name, testFn)
|
||||
.clearVariable("NCCL_LOCAL_REGISTER");
|
||||
}
|
||||
|
||||
// Environment configuration for enabled registration
|
||||
static ProcessIsolatedTestRunner::TestConfig
|
||||
makeEnabledConfig(const std::string& name, std::function<void()> testFn) {
|
||||
return ProcessIsolatedTestRunner::TestConfig(name, testFn)
|
||||
.withEnvironment({{"NCCL_LOCAL_REGISTER", "1"}});
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test ncclCommRegister and ncclCommDeregister APIs with process isolation
|
||||
*
|
||||
* This test suite verifies that:
|
||||
* 1. A device buffer can be registered with ncclCommRegister (API returns success)
|
||||
* 2. When NCCL_LOCAL_REGISTER=1, the registration returns a valid (non-NULL) handle
|
||||
* 3. When NCCL_LOCAL_REGISTER is not set, NULL handle is expected (default behavior)
|
||||
* 4. The buffer can be deregistered with ncclCommDeregister
|
||||
*
|
||||
* Note: NCCL_LOCAL_REGISTER defaults to 0 (disabled) in RCCL.
|
||||
*/
|
||||
TEST(Register, ProcessIsolatedRegisterTests)
|
||||
{
|
||||
RUN_ISOLATED_TESTS(
|
||||
// CommRegisterDeregister tests
|
||||
makeDisabledConfig("CommRegisterDeregister_Disabled",
|
||||
[]() { testCommRegisterDeregister(false); }),
|
||||
makeEnabledConfig("CommRegisterDeregister_Enabled",
|
||||
[]() { testCommRegisterDeregister(true); }),
|
||||
|
||||
// MultipleBufferRegistration tests
|
||||
makeDisabledConfig("MultipleBufferRegistration_Disabled",
|
||||
[]() { testMultipleBufferRegistration(false); }),
|
||||
makeEnabledConfig("MultipleBufferRegistration_Enabled",
|
||||
[]() { testMultipleBufferRegistration(true); }),
|
||||
|
||||
// VariableSizeBuffers tests
|
||||
makeDisabledConfig("VariableSizeBuffers_Disabled",
|
||||
[]() { testVariableSizeBuffers(false); }),
|
||||
makeEnabledConfig("VariableSizeBuffers_Enabled",
|
||||
[]() { testVariableSizeBuffers(true); }),
|
||||
|
||||
// DeregisterNullHandle test (no enable/disable variants needed)
|
||||
ProcessIsolatedTestRunner::TestConfig("DeregisterNullHandle", testDeregisterNullHandle)
|
||||
);
|
||||
}
|
||||
|
||||
} // namespace RcclUnitTesting
|
||||
@@ -192,8 +192,8 @@ namespace RcclUnitTesting
|
||||
case ncclCollAllReduce: ss << "ncclAllReduce"; break;
|
||||
case ncclCollGather: ss << "ncclGather"; break;
|
||||
case ncclCollScatter: ss << "ncclScatter"; break;
|
||||
case ncclCollAllToAll: ss << "ncclAllToAll"; break;
|
||||
case ncclCollAllToAllv: ss << "ncclAllToAllv"; break;
|
||||
case ncclCollAlltoAll: ss << "ncclAlltoAll"; break;
|
||||
case ncclCollAlltoAllv: ss << "ncclAlltoAllv"; break;
|
||||
case ncclCollSend: ss << "ncclSend"; break;
|
||||
case ncclCollRecv: ss << "ncclRecv"; break;
|
||||
default: ss << "[Unknown]"; break;
|
||||
@@ -276,7 +276,7 @@ namespace RcclUnitTesting
|
||||
*numInputElements = totalRanks * N;
|
||||
*numOutputElements = N;
|
||||
break;
|
||||
case ncclCollAllToAll:
|
||||
case ncclCollAlltoAll:
|
||||
*numInputElements = totalRanks * N;
|
||||
*numOutputElements = totalRanks * N;
|
||||
break;
|
||||
|
||||
@@ -20,8 +20,8 @@ namespace RcclUnitTesting
|
||||
ncclCollAllReduce,
|
||||
ncclCollGather,
|
||||
ncclCollScatter,
|
||||
ncclCollAllToAll,
|
||||
ncclCollAllToAllv,
|
||||
ncclCollAlltoAll,
|
||||
ncclCollAlltoAllv,
|
||||
ncclCollSend,
|
||||
ncclCollRecv,
|
||||
ncclNumFuncs
|
||||
@@ -36,8 +36,8 @@ namespace RcclUnitTesting
|
||||
"AllReduce",
|
||||
"Gather",
|
||||
"Scatter",
|
||||
"AllToAll",
|
||||
"AllToAllv",
|
||||
"AlltoAll",
|
||||
"AlltoAllv",
|
||||
"Send",
|
||||
"Recv"
|
||||
};
|
||||
|
||||
@@ -22,8 +22,8 @@ namespace RcclUnitTesting
|
||||
case ncclCollAllReduce: return DefaultPrepData_Reduce(collArgs, true);
|
||||
case ncclCollGather: return DefaultPrepData_Gather(collArgs, false);
|
||||
case ncclCollScatter: return DefaultPrepData_Scatter(collArgs);
|
||||
case ncclCollAllToAll: return DefaultPrepData_AllToAll(collArgs);
|
||||
case ncclCollAllToAllv: return DefaultPrepData_AllToAllv(collArgs);
|
||||
case ncclCollAlltoAll: return DefaultPrepData_AllToAll(collArgs);
|
||||
case ncclCollAlltoAllv: return DefaultPrepData_AllToAllv(collArgs);
|
||||
case ncclCollSend: return DefaultPrepData_Send(collArgs);
|
||||
case ncclCollRecv: return DefaultPrepData_Recv(collArgs);
|
||||
default:
|
||||
|
||||
@@ -402,6 +402,9 @@ bool ProcessIsolatedTestRunner::executeAllTests(const ExecutionOptions& options)
|
||||
continue;
|
||||
}
|
||||
|
||||
// Flush all output before fork to prevent child from inheriting unflushed buffers
|
||||
fflush(NULL);
|
||||
|
||||
pid_t pid = fork();
|
||||
|
||||
if(pid == 0)
|
||||
@@ -435,6 +438,10 @@ bool ProcessIsolatedTestRunner::executeAllTests(const ExecutionOptions& options)
|
||||
{
|
||||
INFO("Running isolated test '%s' (PID: %d)\n", testConfig.name.c_str(), pid);
|
||||
}
|
||||
// Flush parent's output before reading from child pipes to ensure proper ordering
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
|
||||
int status;
|
||||
CapturedOutput output = captureProcessOutput(stdout_fd, stderr_fd, pid, &status);
|
||||
|
||||
@@ -442,6 +449,9 @@ bool ProcessIsolatedTestRunner::executeAllTests(const ExecutionOptions& options)
|
||||
auto duration
|
||||
= std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime);
|
||||
|
||||
// Display captured output BEFORE status messages for proper sequencing
|
||||
displayCapturedOutput(output, testConfig.name);
|
||||
|
||||
TestResult testResult;
|
||||
testResult.testName = testConfig.name;
|
||||
testResult.processId = pid;
|
||||
@@ -530,8 +540,6 @@ bool ProcessIsolatedTestRunner::executeAllTests(const ExecutionOptions& options)
|
||||
testResult.errorMessage = "Failed to wait for process";
|
||||
}
|
||||
|
||||
displayCapturedOutput(output, testConfig.name);
|
||||
|
||||
recordTestResult(testResult);
|
||||
|
||||
// Stop on first failure if requested
|
||||
|
||||
@@ -647,18 +647,18 @@ namespace RcclUnitTesting
|
||||
this->streams[groupId][localRank][collArg.streamIdx]),
|
||||
"ncclScatter");
|
||||
break;
|
||||
case ncclCollAllToAll:
|
||||
CHILD_NCCL_CALL_RANK(errCode, ncclAllToAll(
|
||||
case ncclCollAlltoAll:
|
||||
CHILD_NCCL_CALL_RANK(errCode, ncclAlltoAll(
|
||||
collArg.inputGpu.ptr,
|
||||
collArg.outputGpu.ptr,
|
||||
collArg.numInputElements / collArg.totalRanks,
|
||||
collArg.dataType,
|
||||
this->comms[localRank],
|
||||
this->streams[groupId][localRank][collArg.streamIdx]),
|
||||
"ncclAllToAll");
|
||||
"ncclAlltoAll");
|
||||
break;
|
||||
case ncclCollAllToAllv:
|
||||
CHILD_NCCL_CALL_RANK(errCode, ncclAllToAllv(
|
||||
case ncclCollAlltoAllv:
|
||||
CHILD_NCCL_CALL_RANK(errCode, ncclAlltoAllv(
|
||||
collArg.inputGpu.ptr,
|
||||
collArg.options.sendcounts + (this->rankOffset + localRank)*this->totalRanks,
|
||||
collArg.options.sdispls + (this->rankOffset + localRank)*this->totalRanks,
|
||||
@@ -668,7 +668,7 @@ namespace RcclUnitTesting
|
||||
collArg.dataType,
|
||||
this->comms[localRank],
|
||||
this->streams[groupId][localRank][collArg.streamIdx]),
|
||||
"ncclAllToAllv");
|
||||
"ncclAlltoAllv");
|
||||
break;
|
||||
case ncclCollSend:
|
||||
CHILD_NCCL_CALL_RANK(errCode, ncclSend(
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "proxy_trace/proxy_trace.h"
|
||||
#include <cstdint>
|
||||
#include <gtest/gtest.h>
|
||||
#include <memory>
|
||||
#include <unistd.h>
|
||||
namespace RcclUnitTesting {
|
||||
|
||||
@@ -21,7 +22,7 @@ public:
|
||||
int nSteps = 10;
|
||||
void SetUp() override {
|
||||
proxyState = new ncclProxyState();
|
||||
facebook_rccl::proxyTraceInit(proxyState->proxyTrace, 0, commHash);
|
||||
proxyState->proxyTrace = std::make_unique<facebook_rccl::ProxyTrace>(0);
|
||||
EXPECT_NE(proxyState->proxyTrace, nullptr);
|
||||
sub1 = new ncclProxySubArgs();
|
||||
sub2 = new ncclProxySubArgs();
|
||||
@@ -36,9 +37,12 @@ public:
|
||||
delete proxyState;
|
||||
}
|
||||
void AddTraceOp(ncclProxySubArgs *sub, facebook_rccl::ProxyOpType opType) {
|
||||
facebook_rccl::addNewProxyOp(proxyState->proxyTrace, sub->traceKey,
|
||||
sub->traceInfo, opType, sub->channelId,
|
||||
sub->nsteps, sub->nbytes, sub->peer);
|
||||
proxyState->proxyTrace->addNewProxyOp(
|
||||
sub->traceKey,
|
||||
sub->traceInfo,
|
||||
opType,
|
||||
sub->channelId,
|
||||
sub->nsteps, sub->nbytes, sub->peer);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -49,16 +53,10 @@ TEST_F(ProxyTraceTestFixture, nonEmptySingleton) {
|
||||
|
||||
TEST_F(ProxyTraceTestFixture, addTraceOp) {
|
||||
auto &tracer = proxyState->proxyTrace;
|
||||
EXPECT_EQ(tracer->getOrCreateProxyOpId(sub1->traceKey.commHash,
|
||||
sub1->traceKey.opCount),
|
||||
0);
|
||||
AddTraceOp(sub1, facebook_rccl::ProxyOpType::SEND);
|
||||
EXPECT_EQ(sub1->traceKey.proxyOpId, 0);
|
||||
AddTraceOp(sub2, facebook_rccl::ProxyOpType::RECV);
|
||||
EXPECT_EQ(sub2->traceKey.proxyOpId, 1);
|
||||
EXPECT_EQ(tracer->getOrCreateProxyOpId(sub1->traceKey.commHash,
|
||||
sub1->traceKey.opCount),
|
||||
2);
|
||||
auto traceRecordPtr = tracer->getProxyTraceOpPtr(sub1->traceKey);
|
||||
EXPECT_EQ(traceRecordPtr->opType, facebook_rccl::ProxyOpType::SEND);
|
||||
}
|
||||
@@ -73,9 +71,10 @@ TEST_F(ProxyTraceTestFixture, getMapSizeMB) {
|
||||
EXPECT_GT(size2, size1);
|
||||
// finish sub1
|
||||
sub1->done = nSteps;
|
||||
facebook_rccl::updateProxyOpCounter(tracer, sub1->traceKey,
|
||||
facebook_rccl::ProxyCounterTypes::DONE,
|
||||
sub1->done);
|
||||
tracer->updateProxyOpCounter(
|
||||
sub1->traceKey,
|
||||
facebook_rccl::ProxyCounterTypes::DONE,
|
||||
sub1->done);
|
||||
// sub1 is now serialized and should be moved from activeOps to finishedOps
|
||||
auto size3 = tracer->getMapSizeMB();
|
||||
EXPECT_GT(size3, size1);
|
||||
@@ -84,13 +83,14 @@ TEST_F(ProxyTraceTestFixture, getMapSizeMB) {
|
||||
TEST_F(ProxyTraceTestFixture, updateTraceOp) {
|
||||
auto &tracer = proxyState->proxyTrace;
|
||||
AddTraceOp(sub1, facebook_rccl::ProxyOpType::SEND);
|
||||
facebook_rccl::updateProxyOpCounter(
|
||||
tracer, sub1->traceKey,
|
||||
facebook_rccl::ProxyCounterTypes::KERNEL_COPY_READY, 1);
|
||||
facebook_rccl::updateProxyOpCounter(
|
||||
tracer, sub1->traceKey, facebook_rccl::ProxyCounterTypes::POSTED, 3);
|
||||
facebook_rccl::updateProxyOpCounter(
|
||||
tracer, sub1->traceKey, facebook_rccl::ProxyCounterTypes::TRANSMITTED, 2);
|
||||
tracer->updateProxyOpCounter(
|
||||
sub1->traceKey,
|
||||
facebook_rccl::ProxyCounterTypes::KERNEL_COPY_READY,
|
||||
1);
|
||||
tracer->updateProxyOpCounter(
|
||||
sub1->traceKey, facebook_rccl::ProxyCounterTypes::POSTED, 3);
|
||||
tracer->updateProxyOpCounter(
|
||||
sub1->traceKey, facebook_rccl::ProxyCounterTypes::TRANSMITTED, 2);
|
||||
|
||||
auto traceRecordPtr = tracer->getProxyTraceOpPtr(sub1->traceKey);
|
||||
EXPECT_NE(traceRecordPtr, nullptr);
|
||||
@@ -110,25 +110,12 @@ TEST_F(ProxyTraceTestFixture, updateTraceOp2) {
|
||||
AddTraceOp(sub1, facebook_rccl::ProxyOpType::SEND);
|
||||
int64_t rand = 123456789;
|
||||
sub1->posted = rand;
|
||||
facebook_rccl::updateProxyOpCounter(tracer, sub1->traceKey,
|
||||
facebook_rccl::ProxyCounterTypes::POSTED,
|
||||
sub1->posted);
|
||||
tracer->updateProxyOpCounter(sub1->traceKey,
|
||||
facebook_rccl::ProxyCounterTypes::POSTED,
|
||||
sub1->posted);
|
||||
auto traceRecordPtr = tracer->getProxyTraceOpPtr(sub1->traceKey);
|
||||
EXPECT_EQ(traceRecordPtr->counters[facebook_rccl::ProxyCounterTypes::POSTED],
|
||||
rand);
|
||||
}
|
||||
|
||||
TEST_F(ProxyTraceTestFixture, memoryReclaim) {
|
||||
auto &tracer = proxyState->proxyTrace;
|
||||
tracer->resetAll();
|
||||
AddTraceOp(sub1, facebook_rccl::ProxyOpType::SEND);
|
||||
sub1->done = nSteps;
|
||||
facebook_rccl::updateProxyOpCounter(tracer, sub1->traceKey,
|
||||
facebook_rccl::ProxyCounterTypes::DONE,
|
||||
sub1->done);
|
||||
auto traceRecordPtr = tracer->getProxyTraceOpPtr(sub1->traceKey);
|
||||
EXPECT_EQ(traceRecordPtr, nullptr);
|
||||
EXPECT_GT(tracer->getMapSizeMB(), 0);
|
||||
}
|
||||
|
||||
} // namespace RcclUnitTesting
|
||||
} // namespace RcclUnitTesting
|
||||
|
||||
Criar uma nova questão referindo esta
Bloquear um utilizador