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.
This commit is contained in:
+18
-11
@@ -48,17 +48,19 @@ ncclResult_t ncclSocketInit(ncclDebugLogger_t logFunction) {
|
||||
WARN("NET/Socket : no interface found");
|
||||
return ncclInternalError;
|
||||
} else {
|
||||
char line[1024];
|
||||
char addrline[1024];
|
||||
#define MAX_LINE_LEN (2047)
|
||||
char line[MAX_LINE_LEN+1];
|
||||
char addrline[SOCKET_NAME_MAXLEN+1];
|
||||
line[0] = '\0';
|
||||
addrline[SOCKET_NAME_MAXLEN] = '\0';
|
||||
for (int i=0; i<ncclNetIfs; i++) {
|
||||
strcpy(ncclSocketDevs[i].devName, names+i*MAX_IF_NAME_SIZE);
|
||||
memcpy(&ncclSocketDevs[i].addr, addrs+i, sizeof(union socketAddress));
|
||||
NCCLCHECK(ncclSocketGetPciPath(ncclSocketDevs[i].devName, &ncclSocketDevs[i].pciPath));
|
||||
snprintf(line+strlen(line), 1023-strlen(line), " [%d]%s:%s", i, names+i*MAX_IF_NAME_SIZE,
|
||||
snprintf(line+strlen(line), MAX_LINE_LEN-strlen(line), " [%d]%s:%s", i, names+i*MAX_IF_NAME_SIZE,
|
||||
socketToString(&addrs[i].sa, addrline));
|
||||
}
|
||||
line[1023] = '\0';
|
||||
line[MAX_LINE_LEN] = '\0';
|
||||
INFO(NCCL_INIT|NCCL_NET,"NET/Socket : Using%s", line);
|
||||
}
|
||||
}
|
||||
@@ -112,8 +114,7 @@ ncclResult_t GetSocketAddr(int dev, union socketAddress* addr) {
|
||||
|
||||
#define MAX_SOCKETS 64
|
||||
#define MAX_THREADS 16
|
||||
#define MAX_REQUESTS 128
|
||||
#define MAX_QUEUE_LEN MAX_REQUESTS
|
||||
#define MAX_REQUESTS NCCL_NET_MAX_REQUESTS
|
||||
#define MIN_CHUNKSIZE (64*1024)
|
||||
|
||||
NCCL_PARAM(SocketNsocksPerThread, "NSOCKS_PERTHREAD", -2);
|
||||
@@ -149,6 +150,7 @@ struct ncclSocketRequest {
|
||||
|
||||
struct ncclSocketTaskQueue {
|
||||
int next;
|
||||
int len;
|
||||
struct ncclSocketTask* tasks;
|
||||
};
|
||||
|
||||
@@ -188,7 +190,7 @@ void* persistentSocketThread(void *args_) {
|
||||
while (1) {
|
||||
int idle = 1;
|
||||
int mark = myQueue->next; // mark newest task seen
|
||||
for (int i=0; i<MAX_QUEUE_LEN; i+=nSocksPerThread) {
|
||||
for (int i=0; i<myQueue->len; i+=nSocksPerThread) {
|
||||
int repeat;
|
||||
do {
|
||||
repeat = 0;
|
||||
@@ -363,7 +365,11 @@ ncclResult_t ncclSocketGetTask(struct ncclSocketComm* comm, int op, void* data,
|
||||
struct ncclSocketTaskQueue* queue = &res->threadTaskQueue;
|
||||
// create helper threads and prepare per-thread task queue
|
||||
if (queue->tasks == NULL) {
|
||||
NCCLCHECK(ncclCalloc(&queue->tasks, MAX_QUEUE_LEN));
|
||||
// each request can be divided up to nSocks tasks, and
|
||||
// these tasks are distributed to nThreads threads,
|
||||
// we need to make sure each thread queue has enough slots for MAX_REQUESTS
|
||||
queue->len = MAX_REQUESTS * DIVUP(comm->nSocks, comm->nThreads);
|
||||
NCCLCHECK(ncclCalloc(&queue->tasks, queue->len));
|
||||
queue->next = 0;
|
||||
res->comm = comm;
|
||||
pthread_mutex_init(&res->threadLock, NULL);
|
||||
@@ -382,7 +388,7 @@ ncclResult_t ncclSocketGetTask(struct ncclSocketComm* comm, int op, void* data,
|
||||
r->used = 1;
|
||||
*req = r;
|
||||
pthread_mutex_lock(&res->threadLock);
|
||||
queue->next = (queue->next+1)%MAX_QUEUE_LEN;
|
||||
queue->next = (queue->next+1)%queue->len;
|
||||
res->state = start;
|
||||
pthread_cond_signal(&res->threadCond);
|
||||
pthread_mutex_unlock(&res->threadLock);
|
||||
@@ -420,6 +426,7 @@ ncclResult_t ncclSocketTest(void* request, int* done, int* size) {
|
||||
// divide into subtasks
|
||||
int chunkOffset = 0, i = 0;
|
||||
if (r->comm->nSocks > 0) {
|
||||
// each request can be divided up to nSocks tasks
|
||||
int taskSize = std::max(MIN_CHUNKSIZE, DIVUP(r->size, r->comm->nSocks));
|
||||
while (chunkOffset < r->size) {
|
||||
int chunkSize = std::min(taskSize, r->size-chunkOffset);
|
||||
@@ -477,7 +484,7 @@ ncclResult_t ncclSocketIrecv(void* recvComm, void* data, int size, void* mhandle
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
ncclResult_t ncclSocketFlush(void* recvComm, void* data, int size, void* mhandle) {
|
||||
ncclResult_t ncclSocketIflush(void* recvComm, void* data, int size, void* mhandle, void** request) {
|
||||
// We don't support CUDA pointers, so we don't need a flush operation
|
||||
return ncclInternalError;
|
||||
}
|
||||
@@ -526,7 +533,7 @@ ncclNet_t ncclNetSocket = {
|
||||
ncclSocketDeregMr,
|
||||
ncclSocketIsend,
|
||||
ncclSocketIrecv,
|
||||
ncclSocketFlush,
|
||||
ncclSocketIflush,
|
||||
ncclSocketTest,
|
||||
ncclSocketClose,
|
||||
ncclSocketClose,
|
||||
|
||||
Reference in New Issue
Block a user