142860442a
* Added MPI support to execute unit/functional tests
Update node and process validation
Updated node detection count and modified validation method
Update validation logic to include max procs and nodes
* Address review comments
* Fix warnings
* Added a new NET transport test and clean up
* Added MPI test logging mechanism
* Decoupled GTest framework
* Added Net IB functional tests
* Updated with resource guards
* Added NET IB tests and refactored code
* Update P2pWorkflow test
* Update documentation
* Add MPI_TESTS_ENABLED guard to the file
* Fix Shm and NetIB tests
* Applied refactoring and cleanup
* Replaced BufferGuard with AutoGuard
* Modified test debug logging
* Use macro to reduce NcclTypeTraits code duplication
- Replace repetitive template specializations with a single
DEFINE_NCCL_TYPE_TRAIT macro
- Use stringification operator (#) to auto-generate type name strings
- Add #undef to keep macro from polluting namespace
- Makes adding new type mappings trivial
* Unify buffer initialization with generic pattern function
- Remove initializeBufferWithCustomPattern
- Make initializeBufferWithPattern generic with PatternFunc template param
- Now single function handles all patterns via lambda injection
- Updated all test files to use lambdas for pattern generation
- Pattern logic now visible at call site (self-documenting)
* Unify buffer verification with pluggable pattern function
- Remove verifyBufferWithCustomCheck
- Make verifyBufferData generic with PatternFunc template param
- Single function handles all verification patterns via lambda injection
- Updated all test files to use lambdas
- Better defaults: num_samples=0 means verify all elements
- Pattern logic now visible at call site (self-documenting)
* Docs: Add DeviceBufferHelpers section to MPITestRunner.md
- Document new refactored buffer initialization/verification API
- Explain pluggable pattern functions with lambda examples
- Show type mapping and automatic float/int comparison
- Include migration guide from old API to new unified functions
- Demonstrate best practices with real-world examples
- Reference recent refactoring commits (macro-based type traits)
* Docs: Update documentation and examples
- Update on DeviceBufferHelpers
- Update examples using DeviceBufferHelpers methods, e.g. data verification
* Address review comment.
- Replace manual pattern generation loop with initializeBufferWithPattern call
- Use downloadBuffer to get host copy instead of manual hipMemcpy
* Remove non-existent dependency
* Remove duplicate testcase
* Code cleanup in test files
* Moved common constants to base class
[ROCm/rccl commit: 29e1567b95]
296 строки
11 KiB
C++
296 строки
11 KiB
C++
/*************************************************************************
|
|
* Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved.
|
|
*
|
|
* See LICENSE.txt for license information
|
|
************************************************************************/
|
|
|
|
#ifndef TRANSPORT_MPI_BASE_HPP
|
|
#define TRANSPORT_MPI_BASE_HPP
|
|
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <vector>
|
|
|
|
#include "rccl/rccl.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
#ifdef MPI_TESTS_ENABLED
|
|
#include "MPITestBase.hpp"
|
|
#include "MPIEnvironment.hpp"
|
|
#include "TestChecks.hpp"
|
|
#include "ResourceGuards.hpp"
|
|
#include "comm.h"
|
|
#include "core.h"
|
|
#include "device.h"
|
|
#include "graph.h"
|
|
#include "graph/topo.h"
|
|
#include "nccl_common.h"
|
|
#include "transport.h"
|
|
|
|
using namespace RCCLTestGuards;
|
|
|
|
// Transport-specific RAII deleters
|
|
namespace RCCLTestGuards
|
|
{
|
|
|
|
struct TransportSendResourceDeleter
|
|
{
|
|
ncclTransport* transport;
|
|
explicit TransportSendResourceDeleter(ncclTransport* t = nullptr) : transport(t) {}
|
|
void operator()(ncclConnector* connector) const
|
|
{
|
|
if(connector && transport)
|
|
{
|
|
transport->send.free(connector);
|
|
}
|
|
}
|
|
};
|
|
|
|
struct TransportRecvResourceDeleter
|
|
{
|
|
ncclTransport* transport;
|
|
explicit TransportRecvResourceDeleter(ncclTransport* t = nullptr) : transport(t) {}
|
|
void operator()(ncclConnector* connector) const
|
|
{
|
|
if(connector && transport)
|
|
{
|
|
transport->recv.free(connector);
|
|
}
|
|
}
|
|
};
|
|
|
|
using TransportSendResourceGuard = ResourceGuard<ncclConnector*, TransportSendResourceDeleter>;
|
|
using TransportRecvResourceGuard = ResourceGuard<ncclConnector*, TransportRecvResourceDeleter>;
|
|
|
|
class TransportResourceGuard
|
|
{
|
|
private:
|
|
ncclConnector* send_connector_;
|
|
ncclConnector* recv_connector_;
|
|
ncclTransport* transport_;
|
|
|
|
public:
|
|
TransportResourceGuard(ncclConnector* send, ncclConnector* recv, ncclTransport* transport)
|
|
: send_connector_(send), recv_connector_(recv), transport_(transport)
|
|
{}
|
|
|
|
~TransportResourceGuard()
|
|
{
|
|
if(recv_connector_ && transport_)
|
|
{
|
|
transport_->recv.free(recv_connector_);
|
|
}
|
|
if(send_connector_ && transport_)
|
|
{
|
|
transport_->send.free(send_connector_);
|
|
}
|
|
}
|
|
|
|
TransportResourceGuard(const TransportResourceGuard&) = delete;
|
|
TransportResourceGuard& operator=(const TransportResourceGuard&) = delete;
|
|
TransportResourceGuard(TransportResourceGuard&&) = delete;
|
|
TransportResourceGuard& operator=(TransportResourceGuard&&) = delete;
|
|
};
|
|
|
|
inline TransportSendResourceGuard makeTransportSendGuard(ncclConnector* connector,
|
|
ncclTransport* transport)
|
|
{
|
|
return TransportSendResourceGuard(connector, TransportSendResourceDeleter(transport));
|
|
}
|
|
|
|
inline TransportRecvResourceGuard makeTransportRecvGuard(ncclConnector* connector,
|
|
ncclTransport* transport)
|
|
{
|
|
return TransportRecvResourceGuard(connector, TransportRecvResourceDeleter(transport));
|
|
}
|
|
|
|
} // namespace RCCLTestGuards
|
|
|
|
extern struct ncclTransport p2pTransport;
|
|
extern struct ncclTransport netTransport;
|
|
extern struct ncclTransport shmTransport;
|
|
|
|
// ============================================================================
|
|
// Transport Test Constants
|
|
// ============================================================================
|
|
|
|
namespace TransportTestConstants
|
|
{
|
|
|
|
// Buffer size constants (common across P2P, SHM, NET tests)
|
|
inline constexpr size_t kDefaultBufferSize = 1024 * sizeof(float); // 4096 bytes
|
|
inline constexpr size_t kSmallBufferSize = 256;
|
|
inline constexpr size_t kMediumBufferSize = 16384; // 16 KB
|
|
inline constexpr size_t kLargeBufferSize = 135168; // ~132 KB
|
|
inline constexpr size_t kVeryLargeBufferSize = 256 * 1024 * 1024; // 256 MB
|
|
inline constexpr size_t kCEMemcpyBufferSize = 256 * 1024 * 1024; // 256 MB (for CE tests)
|
|
|
|
// Pattern generation constants
|
|
inline constexpr int kDefaultPatternMultiplier = 1000; // Standard rank-based patterns
|
|
inline constexpr int kSmallPatternMultiplier = 100; // Smaller patterns (memcpy tests)
|
|
inline constexpr int kLargePatternMultiplier = 1000000; // Large buffer patterns
|
|
inline constexpr int kPatternModulo = 10000; // Wraparound patterns
|
|
inline constexpr int kBytePatternModulo = 256; // uint8_t wraparound
|
|
|
|
// Validation constants
|
|
inline constexpr size_t kMaxValidationElements = 100; // Number of elements to validate
|
|
inline constexpr size_t kMinValidationSamples = 100; // Minimum samples for validation
|
|
inline constexpr size_t kValidationStride = 1000; // Stride for sampling validation
|
|
inline constexpr int kMaxErrorsToReport = 10; // Max errors to display
|
|
|
|
// Test iteration constants
|
|
inline constexpr int kMultipleTransferCount = 5; // Number of sequential transfers
|
|
|
|
} // namespace TransportTestConstants
|
|
|
|
// Common test configuration
|
|
struct TransportTestConfig
|
|
{
|
|
int world_rank{0};
|
|
int world_size{0};
|
|
int peer_rank{0};
|
|
ncclComm_t nccl_comm{nullptr};
|
|
hipStream_t stream{nullptr};
|
|
};
|
|
|
|
// Base class for transport tests with common functionality
|
|
// Inherits from MPITestBase to get validation capabilities
|
|
class TransportTestBase : public MPITestBase
|
|
{
|
|
protected:
|
|
TransportTestConfig config;
|
|
|
|
// Transport connectors (can be used for P2P or NET)
|
|
ncclConnector send_connector = {};
|
|
ncclConnector recv_connector = {};
|
|
|
|
// Track which transport type is initialized
|
|
enum class TransportType
|
|
{
|
|
None,
|
|
P2P,
|
|
SHM,
|
|
Network
|
|
};
|
|
TransportType initialized_transport = TransportType::None;
|
|
|
|
// Core NCCL components
|
|
struct ncclComm* comm_handle = nullptr;
|
|
ncclPeerInfo* local_peer_info = nullptr;
|
|
ncclPeerInfo* remote_peer_info = nullptr;
|
|
ncclTopoGraph* topology_graph = nullptr;
|
|
|
|
// RAII guards for automatic resource cleanup
|
|
// These are managed by helper methods and cleaned up automatically
|
|
std::vector<DeviceBufferAutoGuard> buffer_guards_;
|
|
std::vector<NcclRegHandleGuard> reg_handle_guards_;
|
|
|
|
// Setup and teardown
|
|
void SetUp() override;
|
|
void TearDown() override;
|
|
|
|
// Override createTestCommunicator to also update config
|
|
ncclResult_t createTestCommunicator() override;
|
|
|
|
// Set transport type and initialize connectors
|
|
void setTransportType(TransportType type);
|
|
|
|
// Buffer allocation (unguarded - for manual management)
|
|
void allocateAndInitBuffers(void** send_buffer,
|
|
void** recv_buffer,
|
|
size_t send_bytes,
|
|
size_t recv_bytes);
|
|
|
|
// Buffer allocation with automatic RAII guards
|
|
// store_in_base=true: Guards stored in base class, cleanup at test end
|
|
// store_in_base=false: Guards returned, caller controls cleanup scope
|
|
std::pair<DeviceBufferAutoGuard, DeviceBufferAutoGuard> allocateAndInitBuffersGuarded(void** send_buffer,
|
|
void** recv_buffer,
|
|
size_t send_bytes,
|
|
size_t recv_bytes,
|
|
bool store_in_base = true);
|
|
|
|
// Buffer registration (unguarded - for manual management)
|
|
void preRegisterBuffers(void* send_buffer,
|
|
void* recv_buffer,
|
|
size_t send_bytes,
|
|
size_t recv_bytes,
|
|
void** send_reg_handle,
|
|
void** recv_reg_handle);
|
|
|
|
// Buffer registration with automatic RAII guards
|
|
// store_in_base=true: Guards stored in base class, cleanup at test end
|
|
// store_in_base=false: Guards returned, caller controls cleanup scope
|
|
std::pair<NcclRegHandleGuard, NcclRegHandleGuard>
|
|
preRegisterBuffersGuarded(void* send_buffer,
|
|
void* recv_buffer,
|
|
size_t send_bytes,
|
|
size_t recv_bytes,
|
|
void** send_reg_handle,
|
|
void** recv_reg_handle,
|
|
bool store_in_base = true);
|
|
};
|
|
|
|
// ============================================================================
|
|
// Generic Stream Synchronization Helpers
|
|
// ============================================================================
|
|
|
|
/**
|
|
* @brief Generic stream synchronization helper
|
|
*
|
|
* Synchronizes a HIP stream and returns the error code. This function is
|
|
* marked [[nodiscard]] to ensure callers check the return value.
|
|
*
|
|
* @param stream HIP stream to synchronize
|
|
* @param rank MPI rank (for error reporting, currently unused but allows
|
|
* future enhancement with rank-specific error messages)
|
|
* @return hipError_t Result of hipStreamSynchronize
|
|
*
|
|
* Usage examples:
|
|
* - Manual error checking: hipError_t err = syncStream(stream, rank);
|
|
* - With HIPCHECK macro: HIPCHECK(syncStream(stream, rank));
|
|
* - With assertion macro: ASSERT_STREAM_SYNC(stream, rank);
|
|
*/
|
|
[[nodiscard]] inline hipError_t syncStream(hipStream_t stream, int rank = 0)
|
|
{
|
|
return hipStreamSynchronize(stream);
|
|
}
|
|
|
|
/**
|
|
* @def ASSERT_STREAM_SYNC
|
|
* @brief Macro to assert stream synchronization succeeds
|
|
*
|
|
* Convenience macro that combines syncStream() with ASSERT_EQ to provide
|
|
* clean, consistent stream synchronization checks in tests.
|
|
*
|
|
* @param stream HIP stream to synchronize
|
|
* @param rank MPI rank for error reporting
|
|
*
|
|
* Example: ASSERT_STREAM_SYNC(config.stream, config.world_rank);
|
|
*/
|
|
#define ASSERT_STREAM_SYNC(stream, rank) \
|
|
ASSERT_EQ(hipSuccess, syncStream(stream, rank)) \
|
|
<< "Rank " << rank << ": Stream synchronization failed"
|
|
|
|
/**
|
|
* @def ASSERT_STREAM_SYNC_MPI
|
|
* @brief MPI-aware stream synchronization assertion
|
|
*
|
|
* Uses ASSERT_MPI_EQ to ensure all ranks synchronize before failing.
|
|
* This prevents deadlocks when one rank fails while others are waiting
|
|
* in collective operations.
|
|
*
|
|
* @param stream HIP stream to synchronize
|
|
* @param rank MPI rank for error reporting
|
|
*
|
|
* Example: ASSERT_STREAM_SYNC_MPI(config.stream, config.world_rank);
|
|
*
|
|
* @note Prefer this version in multi-rank tests to avoid hangs
|
|
*/
|
|
#define ASSERT_STREAM_SYNC_MPI(stream, rank) ASSERT_MPI_EQ(hipSuccess, syncStream(stream, rank))
|
|
|
|
#endif // MPI_TESTS_ENABLED
|
|
|
|
#endif // TRANSPORT_MPI_BASE_HPP
|