Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 65 additions & 19 deletions include/mscclpp/switch_channel_device.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,11 @@ struct SwitchChannelDeviceHandle {
SwitchChannelDeviceHandle::multimemStore(val, reinterpret_cast<T*>(mcPtr) + index);
}

template <typename VectorType>
/// Vectorized multimem load+reduce. The optional `AccumT` template parameter selects the
/// accumulator: when `AccumT == __half` and `VectorType` is an FP8 vector type, the
/// `.acc::f16` variant of the instruction is used (faster but lower precision than the
/// default FP32 accumulator). For all other types `AccumT` is ignored.
template <typename VectorType, typename AccumT = void>
MSCCLPP_DEVICE_INLINE static VectorType multimemLoadReduce(VectorType* ptr) {
VectorType val;
if constexpr (std::is_same_v<VectorType, i32x1>) {
Expand Down Expand Up @@ -81,29 +85,71 @@ struct SwitchChannelDeviceHandle {
: "l"(ptr)
: "memory");
} else if constexpr (std::is_same_v<VectorType, f8_e4m3x4>) {
asm("multimem.ld_reduce.relaxed.sys.global.add.e4m3x4 %0, [%1];" : "=r"(val.words[0]) : "l"(ptr) : "memory");
if constexpr (std::is_same_v<AccumT, __half>) {
asm("multimem.ld_reduce.relaxed.sys.global.add.acc::f16.e4m3x4 %0, [%1];"
: "=r"(val.words[0])
: "l"(ptr)
: "memory");
} else {
asm("multimem.ld_reduce.relaxed.sys.global.add.e4m3x4 %0, [%1];" : "=r"(val.words[0]) : "l"(ptr) : "memory");
}
} else if constexpr (std::is_same_v<VectorType, f8_e4m3x8>) {
asm("multimem.ld_reduce.relaxed.sys.global.add.v2.e4m3x4 {%0,%1}, [%2];"
: "=r"(val.words[0]), "=r"(val.words[1])
: "l"(ptr)
: "memory");
if constexpr (std::is_same_v<AccumT, __half>) {
asm("multimem.ld_reduce.relaxed.sys.global.add.acc::f16.v2.e4m3x4 {%0,%1}, [%2];"
: "=r"(val.words[0]), "=r"(val.words[1])
: "l"(ptr)
: "memory");
} else {
asm("multimem.ld_reduce.relaxed.sys.global.add.v2.e4m3x4 {%0,%1}, [%2];"
: "=r"(val.words[0]), "=r"(val.words[1])
: "l"(ptr)
: "memory");
}
} else if constexpr (std::is_same_v<VectorType, f8_e4m3x16>) {
asm("multimem.ld_reduce.relaxed.sys.global.add.v4.e4m3x4 {%0,%1,%2,%3}, [%4];"
: "=r"(val.words[0]), "=r"(val.words[1]), "=r"(val.words[2]), "=r"(val.words[3])
: "l"(ptr)
: "memory");
if constexpr (std::is_same_v<AccumT, __half>) {
asm("multimem.ld_reduce.relaxed.sys.global.add.acc::f16.v4.e4m3x4 {%0,%1,%2,%3}, [%4];"
: "=r"(val.words[0]), "=r"(val.words[1]), "=r"(val.words[2]), "=r"(val.words[3])
: "l"(ptr)
: "memory");
} else {
asm("multimem.ld_reduce.relaxed.sys.global.add.v4.e4m3x4 {%0,%1,%2,%3}, [%4];"
: "=r"(val.words[0]), "=r"(val.words[1]), "=r"(val.words[2]), "=r"(val.words[3])
: "l"(ptr)
: "memory");
}
} else if constexpr (std::is_same_v<VectorType, f8_e5m2x4>) {
asm("multimem.ld_reduce.relaxed.sys.global.add.e5m2x4 %0, [%1];" : "=r"(val.words[0]) : "l"(ptr) : "memory");
if constexpr (std::is_same_v<AccumT, __half>) {
asm("multimem.ld_reduce.relaxed.sys.global.add.acc::f16.e5m2x4 %0, [%1];"
: "=r"(val.words[0])
: "l"(ptr)
: "memory");
} else {
asm("multimem.ld_reduce.relaxed.sys.global.add.e5m2x4 %0, [%1];" : "=r"(val.words[0]) : "l"(ptr) : "memory");
}
} else if constexpr (std::is_same_v<VectorType, f8_e5m2x8>) {
asm("multimem.ld_reduce.relaxed.sys.global.add.v2.e5m2x4 {%0,%1}, [%2];"
: "=r"(val.words[0]), "=r"(val.words[1])
: "l"(ptr)
: "memory");
if constexpr (std::is_same_v<AccumT, __half>) {
asm("multimem.ld_reduce.relaxed.sys.global.add.acc::f16.v2.e5m2x4 {%0,%1}, [%2];"
: "=r"(val.words[0]), "=r"(val.words[1])
: "l"(ptr)
: "memory");
} else {
asm("multimem.ld_reduce.relaxed.sys.global.add.v2.e5m2x4 {%0,%1}, [%2];"
: "=r"(val.words[0]), "=r"(val.words[1])
: "l"(ptr)
: "memory");
}
} else if constexpr (std::is_same_v<VectorType, f8_e5m2x16>) {
asm("multimem.ld_reduce.relaxed.sys.global.add.v4.e5m2x4 {%0,%1,%2,%3}, [%4];"
: "=r"(val.words[0]), "=r"(val.words[1]), "=r"(val.words[2]), "=r"(val.words[3])
: "l"(ptr)
: "memory");
if constexpr (std::is_same_v<AccumT, __half>) {
asm("multimem.ld_reduce.relaxed.sys.global.add.acc::f16.v4.e5m2x4 {%0,%1,%2,%3}, [%4];"
: "=r"(val.words[0]), "=r"(val.words[1]), "=r"(val.words[2]), "=r"(val.words[3])
: "l"(ptr)
: "memory");
} else {
asm("multimem.ld_reduce.relaxed.sys.global.add.v4.e5m2x4 {%0,%1,%2,%3}, [%4];"
: "=r"(val.words[0]), "=r"(val.words[1]), "=r"(val.words[2]), "=r"(val.words[3])
: "l"(ptr)
: "memory");
}
} else {
static_assert(dependentFalse<VectorType>, "Not supported type");
}
Expand Down
38 changes: 18 additions & 20 deletions src/ext/collectives/allreduce/allreduce_nvls_block_pipeline.cu
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace collective {

__device__ DeviceSemaphore deviceSemaphore[NUM_SEMAPHORES];

template <typename T>
template <typename T, typename AccumT = T>
__global__ void __launch_bounds__(1024, 1)
allreduceNvlsBlockPipeline([[maybe_unused]] const void* src, [[maybe_unused]] void* scratch,
[[maybe_unused]] void* dst,
Expand Down Expand Up @@ -105,7 +105,7 @@ __global__ void __launch_bounds__(1024, 1)
deviceSemaphore[oriBid].acquire();
}
__syncthreads();
handleMultiLoadReduceStore(mcBuff, mcBuff, offset, offset, reduceIterSize, tid, blockDim.x);
handleMultiLoadReduceStore<T, AccumT>(mcBuff, mcBuff, offset, offset, reduceIterSize, tid, blockDim.x);
__syncthreads();
if (tid == 0) {
deviceSemaphore[nBlocksForCopy + bidForReduce * copyReduceRatio + i].release();
Expand Down Expand Up @@ -158,24 +158,19 @@ struct NvlsBlockPipelineAdapter {
} else if constexpr (std::is_same_v<T, __fp8_e4m3b15>) {
// fp8_e4m3b15 is a software-only type with no hardware NVLS support.
return cudaErrorNotSupported;
} else
#if defined(__CUDA_ARCH__) // Skip the __CUDA_ARCH__ < 1000 since FP8 has not been supported for NVLS
if constexpr (std::is_same_v<T, __fp8_e4m3> || std::is_same_v<T, __fp8_e5m2>) {
return cudaErrorNotSupported;
} else
#endif
{
using ChannelType = DeviceHandle<BaseMemoryChannel>;
allreduceNvlsBlockPipeline<T>
<<<nBlocks, nThreadsPerBlock, 0, stream>>>(input, scratch, output, (ChannelType*)memoryChannels,
nvlsChannels, inputSize, scratchBufferSize, rank, nRanksPerNode);
return cudaGetLastError();
}
} else {
using ChannelType = DeviceHandle<BaseMemoryChannel>;
allreduceNvlsBlockPipeline<T, AccumT>
<<<nBlocks, nThreadsPerBlock, 0, stream>>>(input, scratch, output, (ChannelType*)memoryChannels, nvlsChannels,
inputSize, scratchBufferSize, rank, nRanksPerNode);
return cudaGetLastError();
}
}
};

void AllreduceNvlsBlockPipeline::initialize(std::shared_ptr<Communicator> comm) {
nSwitchChannels_ = 8;
fp8NvlsSupported_ = isFp8NvlsSupported();
int nBaseChannels = 64;
this->conns_ = setupConnections(comm);
// setup semaphores
Expand All @@ -187,12 +182,15 @@ void AllreduceNvlsBlockPipeline::initialize(std::shared_ptr<Communicator> comm)
this->nvlsConnections_ = setupNvlsConnections(comm, nvlsBufferSize_, nSwitchChannels_);
}

CommResult AllreduceNvlsBlockPipeline::allreduceKernelFunc(const std::shared_ptr<void> ctx_void, const void* input,
void* output, size_t inputSize, DataType dtype, ReduceOp op,
cudaStream_t stream, int nBlocks, int nThreadsPerBlock,
const std::unordered_map<std::string, uintptr_t>& extras,
DataType accumDtype) {
CommResult AllreduceNvlsBlockPipeline::allreduceKernelFunc(
const std::shared_ptr<void> ctx_void, const void* input, void* output, size_t inputSize, DataType dtype,
ReduceOp op, cudaStream_t stream, int nBlocks, int nThreadsPerBlock,
[[maybe_unused]] const std::unordered_map<std::string, uintptr_t>& extras, DataType accumDtype) {
auto ctx = std::static_pointer_cast<AlgorithmCtx>(ctx_void);
if (isNativeFp8DataType(dtype) && !fp8NvlsSupported_) {
WARN("FP8 NVLS allreduce requires device support for FP8 multimem reduction.");
return CommResult::CommInvalidArgument;
}
AllreduceFunc allreduce = dispatch<NvlsBlockPipelineAdapter>(op, dtype, accumDtype);
if (!allreduce) {
Comment thread
Binyang2014 marked this conversation as resolved.
WARN("Unsupported operation or data type for allreduce, dtype=%d", static_cast<int>(dtype));
Expand Down
30 changes: 15 additions & 15 deletions src/ext/collectives/allreduce/allreduce_nvls_warp_pipeline.cu
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
namespace mscclpp {
namespace collective {

template <typename T>
template <typename T, typename AccumT = T>
__global__ void __launch_bounds__(1024, 1)
allreduceNvlsWarpPipeline([[maybe_unused]] const void* src, [[maybe_unused]] void* scratch,
[[maybe_unused]] void* dst,
Expand Down Expand Up @@ -85,7 +85,8 @@ __global__ void __launch_bounds__(1024, 1)
asm volatile("bar.sync %0, %1;" ::"r"(1), "r"((NCOPY_WARPS + NREDUCE_WARPS) * WARP_SIZE) : "memory");
T* mcBuff = (T*)multicastPtr->mcPtr;
size_t offset = blockScratchOffset + (it * copyPerIter) % scratchSizePerBlock;
handleMultiLoadReduceStore(mcBuff, mcBuff, offset, offset, iterSize, tidInReduce, NREDUCE_WARPS * WARP_SIZE);
handleMultiLoadReduceStore<T, AccumT>(mcBuff, mcBuff, offset, offset, iterSize, tidInReduce,
NREDUCE_WARPS * WARP_SIZE);
asm volatile("bar.sync %0, %1;" ::"r"(2), "r"((NRECV_COPY_WARPS + NREDUCE_WARPS) * WARP_SIZE) : "memory");
}
if (warpId >= startRecvCopyWid && warpId < endRecvCopyWid) {
Expand Down Expand Up @@ -121,24 +122,19 @@ struct NvlsWarpPipelineAdapter {
} else if constexpr (std::is_same_v<T, __fp8_e4m3b15>) {
// fp8_e4m3b15 is a software-only type with no hardware NVLS support.
return cudaErrorNotSupported;
} else
#if defined(__CUDA_ARCH__) // Skip the __CUDA_ARCH__ < 1000 since FP8 has not been supported for NVLS
if constexpr (std::is_same_v<T, __fp8_e4m3> || std::is_same_v<T, __fp8_e5m2>) {
return cudaErrorNotSupported;
} else
#endif
{
using ChannelType = DeviceHandle<BaseMemoryChannel>;
allreduceNvlsWarpPipeline<T>
<<<nBlocks, nThreadsPerBlock, 0, stream>>>(input, scratch, output, (ChannelType*)memoryChannels,
nvlsChannels, inputSize, scratchBufferSize, rank, nRanksPerNode);
return cudaGetLastError();
}
} else {
using ChannelType = DeviceHandle<BaseMemoryChannel>;
allreduceNvlsWarpPipeline<T, AccumT>
<<<nBlocks, nThreadsPerBlock, 0, stream>>>(input, scratch, output, (ChannelType*)memoryChannels, nvlsChannels,
inputSize, scratchBufferSize, rank, nRanksPerNode);
return cudaGetLastError();
}
}
};

void AllreduceNvlsWarpPipeline::initialize(std::shared_ptr<Communicator> comm) {
nSwitchChannels_ = 8;
fp8NvlsSupported_ = isFp8NvlsSupported();
int nBaseChannels = 64;
this->conns_ = setupConnections(comm);
// setup semaphores
Expand All @@ -155,6 +151,10 @@ CommResult AllreduceNvlsWarpPipeline::allreduceKernelFunc(
ReduceOp op, cudaStream_t stream, int nBlocks, int nThreadsPerBlock,
[[maybe_unused]] const std::unordered_map<std::string, uintptr_t>& extras, DataType accumDtype) {
auto ctx = std::static_pointer_cast<AlgorithmCtx>(ctx_void);
if (isNativeFp8DataType(dtype) && !fp8NvlsSupported_) {
WARN("FP8 NVLS allreduce requires device support for FP8 multimem reduction.");
return CommResult::CommInvalidArgument;
}
AllreduceFunc allreduce = dispatch<NvlsWarpPipelineAdapter>(op, dtype, accumDtype);
if (!allreduce) {
Comment thread
Binyang2014 marked this conversation as resolved.
WARN("Unsupported operation or data type for allreduce, dtype=%d", static_cast<int>(dtype));
Expand Down
25 changes: 12 additions & 13 deletions src/ext/collectives/allreduce/allreduce_nvls_zero_copy.cu
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace collective {

constexpr int MAX_NBLOCKS = 32;

template <typename T>
template <typename T, typename AccumT = T>
__global__ void __launch_bounds__(1024, 1)
allreduceNvls([[maybe_unused]] mscclpp::DeviceHandle<mscclpp::BaseMemoryChannel>* memoryChannels,
[[maybe_unused]] mscclpp::DeviceHandle<mscclpp::SwitchChannel>* multicast,
Expand Down Expand Up @@ -56,8 +56,8 @@ __global__ void __launch_bounds__(1024, 1)
T* src = (T*)multicastPtr->mcPtr;
T* dst = (T*)multicastOutPtr->mcPtr;
if (curBlockSize > 0) {
handleMultiLoadReduceStore(src, dst, blockOffset + channelInOffset, blockOffset + channelOutOffset, curBlockSize,
threadIdx.x, blockDim.x);
handleMultiLoadReduceStore<T, AccumT>(src, dst, blockOffset + channelInOffset, blockOffset + channelOutOffset,
curBlockSize, threadIdx.x, blockDim.x);
}
__syncthreads();
if (threadIdx.x < nPeers) {
Expand All @@ -80,17 +80,11 @@ struct NvlsAdapter {
} else if constexpr (std::is_same_v<T, __fp8_e4m3b15>) {
// fp8_e4m3b15 is a software-only type with no hardware NVLS support.
return cudaErrorNotSupported;
} else
#if (!defined(__CUDA_ARCH_SPECIFIC__) && !defined(__CUDA_ARCH_FAMILY_SPECIFIC__)) || (__CUDA_ARCH__ < 1000)
if constexpr (std::is_same_v<T, __fp8_e4m3> || std::is_same_v<T, __fp8_e5m2>) {
return cudaErrorNotSupported;
} else
#endif
{
} else {
using ChannelType = DeviceHandle<mscclpp::BaseMemoryChannel>;
allreduceNvls<T><<<nBlocks, nThreadsPerBlock, 0, stream>>>((ChannelType*)memoryChannels, nvlsChannels,
nvlsOutChannels, channelInOffset, channelOutOffset,
inputSize, rank, nRanksPerNode);
allreduceNvls<T, AccumT>
<<<nBlocks, nThreadsPerBlock, 0, stream>>>((ChannelType*)memoryChannels, nvlsChannels, nvlsOutChannels,
channelInOffset, channelOutOffset, inputSize, rank, nRanksPerNode);
return cudaGetLastError();
}
}
Expand All @@ -102,6 +96,7 @@ void AllreduceNvls::initialize(std::shared_ptr<mscclpp::Communicator> comm) {
cudaDeviceProp deviceProp;
MSCCLPP_CUDATHROW(cudaGetDeviceProperties(&deviceProp, device));
computeCapabilityMajor_ = deviceProp.major;
fp8NvlsSupported_ = isFp8NvlsSupported();
nSwitchChannels_ = 32;
this->conns_ = setupConnections(comm);
// setup semaphores
Expand All @@ -124,6 +119,10 @@ CommResult AllreduceNvls::allreduceKernelFunc(const std::shared_ptr<void> ctx_vo
return CommResult::CommInvalidArgument;
}
auto ctx = std::static_pointer_cast<AlgorithmCtx>(ctx_void);
if (isNativeFp8DataType(dtype) && !fp8NvlsSupported_) {
WARN("FP8 NVLS allreduce requires device support for FP8 multimem reduction.");
return CommResult::CommInvalidArgument;
}
AllreduceFunc allreduce = dispatch<NvlsAdapter>(op, dtype, accumDtype);
if (!allreduce) {
WARN("Unsupported operation or data type for allreduce, dtype=%d", static_cast<int>(dtype));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,93 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

#include "collective_utils.hpp"

#include <algorithm>
#include <mscclpp/algorithm.hpp>
#include <mscclpp/core.hpp>
#include <mscclpp/gpu_utils.hpp>
#include <mscclpp/memory_channel.hpp>
#include <mscclpp/switch_channel.hpp>

#include "collective_utils.hpp"

namespace mscclpp {
namespace collective {

namespace {

#if !defined(MSCCLPP_DEVICE_HIP)
__global__ void fp8NvlsSupportProbeKernel(int* supported) {
#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 1000 && \
(defined(__CUDA_ARCH_SPECIFIC__) || defined(__CUDA_ARCH_FAMILY_SPECIFIC__))
*supported = 1;
#else
*supported = 0;
#endif
}

bool detectFp8NvlsSupport() {
AvoidCudaGraphCaptureGuard cgcGuard;
auto supportedDevice = mscclpp::detail::gpuCallocUnique<int>();
int supportedHost = 0;
auto stream = gpuStreamPool()->getStream();

fp8NvlsSupportProbeKernel<<<1, 1, 0, stream>>>(supportedDevice.get());
cudaError_t err = cudaGetLastError();
if (err != cudaSuccess) {
return false;
}

MSCCLPP_CUDATHROW(
cudaMemcpyAsync(&supportedHost, supportedDevice.get(), sizeof(supportedHost), cudaMemcpyDeviceToHost, stream));
err = cudaStreamSynchronize(stream);
if (err != cudaSuccess) {
(void)cudaGetLastError();
return false;
}
return supportedHost != 0;
}
#endif

} // namespace

bool isFp8DataType(DataType dtype) {
return dtype == DataType::FLOAT8_E4M3FN || dtype == DataType::FLOAT8_E4M3FNUZ || dtype == DataType::FLOAT8_E5M2 ||
dtype == DataType::FLOAT8_E5M2FNUZ || dtype == DataType::FLOAT8_E4M3B15;
}

bool isNativeFp8DataType(DataType dtype) {
#if defined(__FP8_TYPES_EXIST__)
#if defined(__FP8_E4M3_IS_FNUZ__)
if (dtype == DataType::FLOAT8_E4M3FNUZ) {
return true;
}
#else
if (dtype == DataType::FLOAT8_E4M3FN) {
return true;
}
#endif
#if defined(__FP8_E5M2_IS_FNUZ__)
if (dtype == DataType::FLOAT8_E5M2FNUZ) {
return true;
}
#else
if (dtype == DataType::FLOAT8_E5M2) {
return true;
}
#endif
#endif
return false;
}

bool isFp8NvlsSupported() {
#if defined(MSCCLPP_DEVICE_HIP)
return false;
#else
static const bool supported = detectFp8NvlsSupport();
return supported;
#endif
}

std::vector<mscclpp::RegisteredMemory> setupRemoteMemories(std::shared_ptr<mscclpp::Communicator> comm, int rank,
mscclpp::RegisteredMemory localMemory) {
std::vector<mscclpp::RegisteredMemory> remoteMemories;
Expand Down
Loading
Loading