2.8.3-1
Optimization for Tree allreduce on A100.
Improve aggregation performance.
Use shared buffers for inter-node send/recv.
Add NVTX profiling hooks.
Accelerate alltoall connections by merging communication for all
channels.
Add support for one hop communication through NVLink, for faster
send/recv communication on cubemesh topologies like DGX-1.
Improve alltoall scheduling to better balance intra/inter node
communication.
Increase send/recv parallelism by 8x, each warp sending or
receiving to a different peer.
Net: move to v4.
Net: make flush operation asynchronous to accelerate alltoall.
Net: define maximum number of requests.
Fix hang when using LL128 protocol after 2^31 steps.
Fix #379 : topology injection failing when using less GPUs than
described in the XML.
Fix #394 : protocol mismatch causing hangs or crashes when using
one GPU per node.
[ROCm/rccl commit: 920dbe5b35]
This commit is contained in:
@@ -60,7 +60,12 @@ static ncclResult_t ncclTopoSetPaths(struct ncclTopoNode* baseNode, struct ncclT
|
||||
struct ncclTopoLinkList* remPath;
|
||||
NCCLCHECK(getPath(system, remNode, baseNode->type, baseNode->id, &remPath));
|
||||
float width = std::min(path->width, link->width);
|
||||
if (remPath->width < width) {
|
||||
|
||||
// allow routing through a GPU only as 1 hop
|
||||
if (node != baseNode && node->type == GPU &&
|
||||
(link->type != LINK_NVL || remNode->type != GPU || path->count > 1)) continue;
|
||||
|
||||
if ((remPath->width == 0 || remPath->count > path->count) && remPath->width < width) {
|
||||
// Find reverse link
|
||||
for (int l=0; l<remNode->nlinks; l++) {
|
||||
if (remNode->links[l].remNode == node) {
|
||||
@@ -80,24 +85,20 @@ static ncclResult_t ncclTopoSetPaths(struct ncclTopoNode* baseNode, struct ncclT
|
||||
|
||||
// Start with path type = link type. PATH and LINK types are supposed to match.
|
||||
// Don't consider LINK_NET as we only care about the NIC->GPU path.
|
||||
int type = link->type == LINK_NET ? 0 : link->type;
|
||||
int type = link->type == LINK_NET ? LINK_LOC : link->type;
|
||||
// Differentiate between one and multiple PCI switches
|
||||
if (type == PATH_PIX && (node->type == PCI || link->remNode->type == PCI) && remPath->count > 3) type = PATH_PXB;
|
||||
if (node->type == PCI && remNode->type == PCI) type = PATH_PXB;
|
||||
// Consider a path going through the CPU as PATH_PHB
|
||||
if (link->type == LINK_PCI && (node->type == CPU || link->remNode->type == CPU)) type = PATH_PHB;
|
||||
// Ignore Power CPU in an NVLink path
|
||||
if (path->type == PATH_NVL && type == PATH_SYS && link->remNode->type == CPU &&
|
||||
link->remNode->cpu.arch == NCCL_TOPO_CPU_ARCH_POWER) type = 0;
|
||||
// Set 1 hop NVLink as NVB
|
||||
if (node->type == GPU && path->type == PATH_NVL && type == PATH_NVL && remPath->count > 1) type = PATH_NVB;
|
||||
|
||||
remPath->type = std::max(path->type, type);
|
||||
|
||||
// Add to the list for the next iteration if not already in the list
|
||||
// Disallow GPUs as intermediate steps for now
|
||||
if (remNode->type != GPU) {
|
||||
int i;
|
||||
for (i=0; i<nextNodeList.count; i++) if (nextNodeList.list[i] == remNode) break;
|
||||
if (i == nextNodeList.count) nextNodeList.list[nextNodeList.count++] = remNode;
|
||||
}
|
||||
int i;
|
||||
for (i=0; i<nextNodeList.count; i++) if (nextNodeList.list[i] == remNode) break;
|
||||
if (i == nextNodeList.count) nextNodeList.list[nextNodeList.count++] = remNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -217,7 +218,7 @@ ncclResult_t ncclGetLevel(int* level, const char* disableEnv, const char* levelE
|
||||
if (l == -1) {
|
||||
char* str = getenv(levelEnv);
|
||||
if (str) {
|
||||
for (int i=0; i<PATH_NET; i++) {
|
||||
for (int i=0; i<=PATH_SYS; i++) {
|
||||
if (strcmp(str, topoPathTypeStr[i]) == 0) {
|
||||
l = i;
|
||||
break;
|
||||
@@ -239,9 +240,10 @@ ncclResult_t ncclGetLevel(int* level, const char* disableEnv, const char* levelE
|
||||
}
|
||||
|
||||
int ncclTopoUserP2pLevel = -1;
|
||||
ncclResult_t ncclTopoCheckP2p(struct ncclTopoSystem* system, int64_t id1, int64_t id2, int* p2p, int *read) {
|
||||
ncclResult_t ncclTopoCheckP2p(struct ncclTopoSystem* system, int64_t id1, int64_t id2, int* p2p, int *read, int* intermediateRank) {
|
||||
*p2p = 0;
|
||||
*read = 0;
|
||||
if (read) *read = 0;
|
||||
if (intermediateRank) *intermediateRank = -1;
|
||||
|
||||
// Get GPUs from topology
|
||||
int g1, g2;
|
||||
@@ -251,7 +253,16 @@ ncclResult_t ncclTopoCheckP2p(struct ncclTopoSystem* system, int64_t id1, int64_
|
||||
// GPU not found, we can't use p2p.
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
|
||||
// Set intermediate GPU rank, if routing through an intermediate GPU.
|
||||
struct ncclTopoLinkList* path = gpu1->paths[GPU]+g2;
|
||||
if (path->count == 2) {
|
||||
struct ncclTopoNode* intermediateNode = path->list[0]->remNode;
|
||||
if (intermediateNode->type == GPU && intermediateRank) {
|
||||
*intermediateRank = intermediateNode->gpu.rank;
|
||||
}
|
||||
}
|
||||
|
||||
// In general, use P2P whenever we can.
|
||||
int p2pLevel = PATH_SYS;
|
||||
@@ -280,7 +291,7 @@ compare:
|
||||
if (path->type == PATH_NVL) {
|
||||
struct ncclTopoNode* gpu2 = system->nodes[GPU].nodes+g2;
|
||||
// Enable P2P Read for Ampere/NVLink only
|
||||
if ((gpu1->gpu.cudaCompCap == gpu2->gpu.cudaCompCap) && (gpu1->gpu.cudaCompCap == 80)) *read = 1;
|
||||
if (read && (gpu1->gpu.cudaCompCap == gpu2->gpu.cudaCompCap) && (gpu1->gpu.cudaCompCap == 80)) *read = 1;
|
||||
}
|
||||
|
||||
return ncclSuccess;
|
||||
@@ -355,8 +366,8 @@ ncclResult_t ncclTopoComputePaths(struct ncclTopoSystem* system, struct ncclPeer
|
||||
|
||||
// Update path when we don't want to / can't use GPU Direct P2P
|
||||
for (int p=0; p<system->nodes[GPU].count; p++) {
|
||||
int p2p, read;
|
||||
NCCLCHECK(ncclTopoCheckP2p(system, system->nodes[GPU].nodes[p].id, system->nodes[GPU].nodes[g].id, &p2p, &read));
|
||||
int p2p;
|
||||
NCCLCHECK(ncclTopoCheckP2p(system, system->nodes[GPU].nodes[p].id, system->nodes[GPU].nodes[g].id, &p2p, NULL, NULL));
|
||||
if (p2p == 0) {
|
||||
// Divert all traffic through the CPU
|
||||
int cpu;
|
||||
@@ -464,8 +475,7 @@ static ncclResult_t ncclTopoGetNchannels(struct ncclTopoSystem* system, int g /*
|
||||
// Local rank
|
||||
path = system->nodes[GPU].nodes[peer].paths[GPU]+g;
|
||||
if (path->type == PATH_NVL) {
|
||||
int sm = system->nodes[GPU].nodes[g].gpu.cudaCompCap;
|
||||
double nvlWidth = sm < 70 ? PASCAL_NVLINK_WIDTH : VOLTA_NVLINK_WIDTH;
|
||||
float nvlWidth = ncclTopoNVLinkSpeed(system->nodes[GPU].nodes[g].gpu.cudaCompCap);
|
||||
*nChannels = 2*std::max(1, (int)(path->width / nvlWidth));
|
||||
} else {
|
||||
*nChannels = 2;
|
||||
|
||||
Fai riferimento in un nuovo problema
Block a user