Use batched P2P to enhance alltoall small message performance (#1902)
* Batch P2P operations (2 per CU/channel) and update channel-part mapping - Revert bitreversal and fix channel mapping to be compatible with P2P batching and avoid hangs - P2P batching is only used for more than 2 nodes to avoid aggregating intra-node traffic when it is dominant for less than 2 nodes * Address single node regression and channel per net peer * Add batching threshold * Add enable switch for batching * Update CHANGELOG.md * Add minor comment change * Update CHANGELOG.md Co-authored-by: Jeffrey Novotny <jnovotny@amd.com> * Update CHANGELOG.md Co-authored-by: Jeffrey Novotny <jnovotny@amd.com>
This commit is contained in:
committed by
GitHub
parent
ba44f170ad
commit
c1e1f2faeb
@@ -16,12 +16,13 @@ ncclResult_t initNvlsChannel(struct ncclComm* comm, int channelId, struct ncclCo
|
||||
ncclResult_t initCollnetChannel(struct ncclComm* comm, int channelId, struct ncclComm* parent, bool share);
|
||||
ncclResult_t freeChannel(struct ncclChannel* channel, int nRanks, int collnetNRanks, int nvlsNRanks);
|
||||
|
||||
inline uint8_t ncclP2pChannelBaseForRound(struct ncclComm* comm, int p2pRound) {
|
||||
inline uint8_t ncclP2pChannelBaseForRound(struct ncclComm* comm, int p2pRound, int p2pBatchEnable = 0) {
|
||||
if (comm->nNodes > 1) {
|
||||
int nodeDelta = p2pRound/comm->maxLocalRanks;
|
||||
int localDelta = p2pRound%comm->maxLocalRanks;
|
||||
int base = nodeDelta*divUp(comm->maxLocalRanks, NCCL_MAX_DEV_WORK_P2P_PER_BATCH);
|
||||
base += localDelta/NCCL_MAX_DEV_WORK_P2P_PER_BATCH;
|
||||
int batchSize = (comm->nNodes > 2 && p2pBatchEnable) ? NCCL_MAX_DEV_WORK_P2P_PER_BATCH : 1;
|
||||
int base = nodeDelta*divUp(comm->maxLocalRanks, batchSize);
|
||||
base += localDelta/batchSize;
|
||||
return base & 0xff;
|
||||
} else {
|
||||
return p2pRound & 0xff;
|
||||
|
||||
+3
-17
@@ -311,29 +311,15 @@ inline __host__ __device__ void ncclP2pPartBounds(int nParts, int part, size_t b
|
||||
}
|
||||
|
||||
// implemented in channel.h
|
||||
inline __host__ uint8_t ncclP2pChannelBaseForRound(struct ncclComm* comm, int p2pRound);
|
||||
inline __host__ uint8_t ncclP2pChannelBaseForRound(struct ncclComm* comm, int p2pRound, int p2pBatchEnable);
|
||||
|
||||
// ncclP2pChannelToPart and ncclP2pChannelForPart are inverses. The device code
|
||||
// uses ncclP2pChannelToPart to determine which part "this" channel is responsible for.
|
||||
inline __host__ int ncclP2pChannelForPart(int nP2pChannels, int base, int part, int nParts, int nNodes) {
|
||||
if (nNodes > 2) {
|
||||
// Only works because nP2pChannels is pow2
|
||||
int nChannelsLog2 = countOneBits(nP2pChannels-1);
|
||||
int delta = reverseBits(part, nChannelsLog2);
|
||||
return (base + delta) & (nP2pChannels-1);
|
||||
} else {
|
||||
return (base * nParts + part) & (nP2pChannels-1);
|
||||
}
|
||||
}
|
||||
inline __device__ int ncclP2pChannelToPart(int nP2pChannels, int base, int channel, int nParts, int nNodes) {
|
||||
if (nNodes > 2) {
|
||||
// Only works because nP2pChannels is pow2
|
||||
int nChannelsLog2 = countOneBits(nP2pChannels-1);
|
||||
int delta = (channel-base) & (nP2pChannels-1);
|
||||
return reverseBits(delta, nChannelsLog2);
|
||||
} else {
|
||||
return (channel - base * nParts) & (nParts-1);
|
||||
}
|
||||
return (channel - base * nParts) & (nP2pChannels-1);
|
||||
}
|
||||
|
||||
struct alignas(16) ncclDevWorkColl {
|
||||
@@ -425,7 +411,7 @@ constexpr size_t ncclDevWorkSize(enum ncclDevWorkType type) {
|
||||
|
||||
#define NCCL_MAX_DEV_WORK_BATCH_BYTES 128
|
||||
#define NCCL_MAX_DEV_WORK_BATCH_COLLS (NCCL_MAX_DEV_WORK_BATCH_BYTES/sizeof(ncclDevWorkColl))
|
||||
#define NCCL_MAX_DEV_WORK_P2P_PER_BATCH 1
|
||||
#define NCCL_MAX_DEV_WORK_P2P_PER_BATCH 2
|
||||
#define NCCL_MAX_DEV_WORK_P2P_ELEMENTS 2
|
||||
struct alignas(16) ncclDevWorkBatch {
|
||||
union {
|
||||
|
||||
Reference in New Issue
Block a user