2018-09-24 16:06:59 -07:00
/*************************************************************************
2022-01-07 06:39:55 -08:00
* Copyright (c) 2016-2022, NVIDIA CORPORATION. All rights reserved.
2018-09-24 16:06:59 -07:00
*
* See LICENSE.txt for license information
************************************************************************/
#include "nccl.h"
#include "core.h"
#include "utils.h"
#include "bootstrap.h"
#include "net.h"
#include <unistd.h>
#include <sys/types.h>
2022-01-07 06:39:55 -08:00
#include "proxy.h"
2023-09-26 05:47:28 -07:00
#include "param.h"
2018-09-24 16:06:59 -07:00
2024-09-10 05:57:10 -07:00
#define BOOTSTRAP_N_CHECK_ABORT 10000
#define BOOTSTRAP_TAG_CONNECT (0x1 << 31)
#define BOOTSTRAP_TAG_ALLGATHER (0x1 << 30)
#define BOOTSTRAP_TAG_COMMSPLIT (0x1 << 29)
#define BOOTSTRAP_TAG_INTRANODE_ALLGATHER (0x1 << 28)
#define BOOTSTRAP_INIT_TIME_CREATE 0
#define BOOTSTRAP_INIT_TIME_SEND 1
#define BOOTSTRAP_INIT_TIME_RECV 2
#define BOOTSTRAP_INIT_TIME_RING 3
#define BOOTSTRAP_INIT_TIME_TOTAL 4
#define BOOTSTRAP_INIT_TIME_DELAY 5
#define BOOTSTRAP_INIT_TIME_N 6
#define BOOTSTRAP_INIT_ROOT_WAIT 0
#define BOOTSTRAP_INIT_ROOT_SEND 1
#define BOOTSTRAP_INIT_ROOT_RECV 2
#define BOOTSTRAP_INIT_ROOT_N 3
#define BOOTSTRAP_PROF_OPEN(time) \
do { \
time = clockNano(); \
} while (0)
#define BOOTSTRAP_PROF_CLOSE(time) \
do { \
time = clockNano() - time; \
} while (0)
#define BOOTSTRAP_PID(i, n) (((i) + (n)) % (n))
// returns the first rank associated to the root. must have root >=0
// if root >= n_roots, it does NOT assume periodicity
static int firstRankFromRoot ( int root , int n_ranks , int nRoots ) {
return root * ( n_ranks / nRoots ) + std :: min ( root , n_ranks % nRoots );
}
// returns the root of a rank, must have rank >=0
// if rank >= n_ranks, it does NOT assume periodicity
static int rootIdFromRank ( int rank , int nRanks , int nRoots ) {
int rmr = nRanks % nRoots ; // rank mod root
int rpr = nRanks / nRoots ; // rank per root
int D = rmr * ( rpr + 1 );
if ( rank < D )
return rank / ( rpr + 1 );
else
return ( rank - D ) / rpr + rmr ;
}
// return the number of child for a root, root will be periodized
static int nRankFromRoot ( int root , int nRanks , int nRoots ) {
int ir = BOOTSTRAP_PID ( root , nRoots );
int rmr = nRanks % nRoots ; // rank mod root
int rpr = nRanks / nRoots ; // rank per root
return rpr + (( ir < rmr ) ? 1 : 0 );
}
// return the local id of a given rank for a given root
// root will be periodize, rank will not
static int localIdFromRoot ( int rank , int root , int nRanks , int nRoots ) {
int ir = BOOTSTRAP_PID ( root , nRoots );
return rank - firstRankFromRoot ( ir , nRanks , nRoots );
}
// return the number of child for a root, root will be periodized
static int isFirstFromRoot ( int rank , int root , int nRanks , int nRoots ) {
return ( rank == firstRankFromRoot ( root , nRanks , nRoots ));
}
2022-11-29 04:27:46 -08:00
struct bootstrapRootArgs {
struct ncclSocket * listenSock ;
uint64_t magic ;
};
2019-06-25 13:22:47 -07:00
/* Init functions */
2020-09-04 14:35:05 -07:00
static char bootstrapNetIfName [ MAX_IF_NAME_SIZE + 1 ];
2022-01-07 06:39:55 -08:00
static union ncclSocketAddress bootstrapNetIfAddr ;
2020-09-04 14:35:05 -07:00
static int bootstrapNetInitDone = 0 ;
2019-06-25 13:22:47 -07:00
pthread_mutex_t bootstrapNetLock = PTHREAD_MUTEX_INITIALIZER ;
2024-09-10 05:57:10 -07:00
NCCL_PARAM ( BootstrapNetEnable , "OOB_NET_ENABLE" , 0 );
2019-06-25 13:22:47 -07:00
ncclResult_t bootstrapNetInit () {
2020-09-04 14:35:05 -07:00
if ( bootstrapNetInitDone == 0 ) {
2019-06-25 13:22:47 -07:00
pthread_mutex_lock ( & bootstrapNetLock );
2020-09-04 14:35:05 -07:00
if ( bootstrapNetInitDone == 0 ) {
2023-09-26 05:47:28 -07:00
const char * env = ncclGetEnv ( "NCCL_COMM_ID" );
2020-09-04 14:35:05 -07:00
if ( env ) {
2022-01-07 06:39:55 -08:00
union ncclSocketAddress remoteAddr ;
2022-11-29 04:27:46 -08:00
if ( ncclSocketGetAddrFromString ( & remoteAddr , env ) != ncclSuccess ) {
2020-09-04 14:35:05 -07:00
WARN ( "Invalid NCCL_COMM_ID, please use format: <ipv4>:<port> or [<ipv6>]:<port> or <hostname>:<port>" );
2023-09-26 05:47:28 -07:00
pthread_mutex_unlock ( & bootstrapNetLock );
2020-09-04 14:35:05 -07:00
return ncclInvalidArgument ;
}
2022-01-07 06:39:55 -08:00
if ( ncclFindInterfaceMatchSubnet ( bootstrapNetIfName , & bootstrapNetIfAddr , & remoteAddr , MAX_IF_NAME_SIZE , 1 ) <= 0 ) {
2020-09-04 14:35:05 -07:00
WARN ( "NET/Socket : No usable listening interface found" );
2023-09-26 05:47:28 -07:00
pthread_mutex_unlock ( & bootstrapNetLock );
2020-09-04 14:35:05 -07:00
return ncclSystemError ;
}
2019-06-25 13:22:47 -07:00
} else {
2022-01-07 06:39:55 -08:00
int nIfs = ncclFindInterfaces ( bootstrapNetIfName , & bootstrapNetIfAddr , MAX_IF_NAME_SIZE , 1 );
2020-09-04 14:35:05 -07:00
if ( nIfs <= 0 ) {
WARN ( "Bootstrap : no socket interface found" );
2023-09-26 05:47:28 -07:00
pthread_mutex_unlock ( & bootstrapNetLock );
2020-09-04 14:35:05 -07:00
return ncclInternalError ;
2019-06-25 13:22:47 -07:00
}
}
2020-09-04 14:35:05 -07:00
char line [ SOCKET_NAME_MAXLEN + MAX_IF_NAME_SIZE + 2 ];
sprintf ( line , " %s:" , bootstrapNetIfName );
2022-01-07 06:39:55 -08:00
ncclSocketToString ( & bootstrapNetIfAddr , line + strlen ( line ));
2024-09-10 05:57:10 -07:00
INFO ( NCCL_BOOTSTRAP , "Bootstrap : Using%s" , line );
2020-09-04 14:35:05 -07:00
bootstrapNetInitDone = 1 ;
2019-06-25 13:22:47 -07:00
}
pthread_mutex_unlock ( & bootstrapNetLock );
}
return ncclSuccess ;
}
2018-09-24 16:06:59 -07:00
2019-06-25 13:22:47 -07:00
/* Socket Interface Selection type */
enum bootstrapInterface_t { findSubnetIf = - 1 , dontCareIf = - 2 };
2024-09-10 05:57:10 -07:00
// check abort function
static ncclResult_t checkAbort ( volatile uint32_t * flag , int * cntr ) {
if (( * cntr % BOOTSTRAP_N_CHECK_ABORT ) == 0 ) {
if ( flag && __atomic_load_n ( flag , __ATOMIC_ACQUIRE )) {
TRACE ( NCCL_BOOTSTRAP , "bootstrap: abort called" );
return ncclInternalError ;
}
}
* cntr = ( * cntr + 1 ) % BOOTSTRAP_N_CHECK_ABORT ;
return ncclSuccess ;
}
// send/recv functions
static ncclResult_t netReg ( ncclNet_t * net , void * comm , void * data , int size , void ** handle ) {
NCCLCHECK ( net -> regMr ( comm , data , size , NCCL_PTR_HOST , handle ));
return ncclSuccess ;
}
static ncclResult_t netDereg ( ncclNet_t * net , void * comm , void ** handle ) {
NCCLCHECK ( net -> deregMr ( comm , * handle ));
* handle = NULL ;
return ncclSuccess ;
}
static ncclResult_t netIsend ( ncclNet_t * net , void * sendComm , void * data , int size , void * dataHandle , int tag , void ** sendReq ,
int * done ) {
if ( * done ) return ncclSuccess ;
if ( !* sendReq ) {
NCCLCHECK ( net -> isend ( sendComm , data , size , tag , dataHandle , sendReq ));
}
if ( * sendReq ) {
NCCLCHECK ( net -> test ( * sendReq , done , NULL ));
if ( * done ) {
* sendReq = NULL ;
}
}
return ncclSuccess ;
}
static ncclResult_t netIrecv ( ncclNet_t * net , void * recvComm , void * data , int size , void * dataHandle , int tag , void ** recvReq ,
int * done ) {
if ( * done ) return ncclSuccess ;
if ( !* recvReq ) {
NCCLCHECK ( net -> irecv ( recvComm , 1 , & data , & size , & tag , & dataHandle , recvReq ));
}
if ( * recvReq ) {
NCCLCHECK ( net -> test ( * recvReq , done , NULL ));
if ( * done ) {
* recvReq = NULL ;
}
}
return ncclSuccess ;
}
static ncclResult_t netSendRecv ( ncclNet_t * net , void * sendComm , void * sendData , int sendSize , void * sendDataHandle , void * recvComm ,
void * recvData , int recvSize , void * recvDataHandle , int tag , volatile uint32_t * abortFlag ) {
int abortCounter = 0 ;
int doneSend = 0 , doneRecv = 0 ;
void * sendReq = NULL , * recvReq = NULL ;
do {
NCCLCHECK ( checkAbort ( abortFlag , & abortCounter ));
if ( ! doneRecv ) {
NCCLCHECK ( netIrecv ( net , recvComm , recvData , recvSize , recvDataHandle , tag , & recvReq , & doneRecv ));
}
if ( ! doneSend ) {
NCCLCHECK ( netIsend ( net , sendComm , sendData , sendSize , sendDataHandle , tag , & sendReq , & doneSend ));
}
} while ( ! doneSend || ! doneRecv );
return ncclSuccess ;
}
// Additional socket based functions, first send the size, then send the message
static ncclResult_t socketSend ( struct ncclSocket * sock , void * data , int size ) {
2022-01-07 06:39:55 -08:00
NCCLCHECK ( ncclSocketSend ( sock , & size , sizeof ( int )));
2024-09-10 05:57:10 -07:00
if ( size > 0 )
NCCLCHECK ( ncclSocketSend ( sock , data , size ));
2018-09-24 16:06:59 -07:00
return ncclSuccess ;
}
2024-09-10 05:57:10 -07:00
static ncclResult_t socketRecv ( struct ncclSocket * sock , void * data , int size ) {
2019-06-25 13:22:47 -07:00
int recvSize ;
2022-01-07 06:39:55 -08:00
NCCLCHECK ( ncclSocketRecv ( sock , & recvSize , sizeof ( int )));
2019-06-25 13:22:47 -07:00
if ( recvSize > size ) {
2021-02-09 15:34:08 -08:00
WARN ( "Message truncated : received %d bytes instead of %d" , recvSize , size );
2019-06-25 13:22:47 -07:00
return ncclInternalError ;
}
2024-09-10 05:57:10 -07:00
int actualSize = std :: min ( recvSize , size );
if ( actualSize > 0 )
NCCLCHECK ( ncclSocketRecv ( sock , data , actualSize ));
2018-09-24 16:06:59 -07:00
return ncclSuccess ;
}
2024-09-10 05:57:10 -07:00
static ncclResult_t socketSendRecv ( struct ncclSocket * sendSock , void * sendData , int sendSize , struct ncclSocket * recvSock ,
void * recvData , int recvSize ) {
2024-03-26 06:08:55 -07:00
int senderRecvSize ;
NCCLCHECK ( ncclSocketSendRecv ( sendSock , & sendSize , sizeof ( int ), recvSock , & senderRecvSize , sizeof ( int )));
if ( senderRecvSize > recvSize ) {
WARN ( "Message truncated : received %d bytes instead of %d" , senderRecvSize , recvSize );
return ncclInternalError ;
}
2024-09-10 05:57:10 -07:00
NCCLCHECK ( ncclSocketSendRecv ( sendSock , sendData , sendSize , recvSock , recvData , std :: min ( recvSize , senderRecvSize )));
2024-03-26 06:08:55 -07:00
return ncclSuccess ;
}
2018-09-24 16:06:59 -07:00
2024-09-10 05:57:10 -07:00
union ringConnectInfo {
union ncclSocketAddress addr ;
char handle [ NCCL_NET_HANDLE_MAXSIZE ];
};
2018-09-24 16:06:59 -07:00
struct extInfo {
2024-09-10 05:57:10 -07:00
int rank ; // rank of the process reaching out
int nranks ; // total number of ranks
int iroot ; // current root index
int nroots ; // total number of roots
union ncclSocketAddress listenRootAddress ; // address of my listenSocket for the root
union ringConnectInfo connectInfo ;
2018-09-24 16:06:59 -07:00
};
2024-09-10 05:57:10 -07:00
#define NET_HANDLE(h, rank) ((h) + (rank * NCCL_NET_HANDLE_MAXSIZE))
#define BOOTSTRAP_HANDLE(h, i) ((struct ncclBootstrapHandle*)((char*)h + i * NCCL_UNIQUE_ID_BYTES))
2018-09-24 16:06:59 -07:00
#include <sys/resource.h>
static ncclResult_t setFilesLimit () {
struct rlimit filesLimit ;
SYSCHECK ( getrlimit ( RLIMIT_NOFILE , & filesLimit ), "getrlimit" );
filesLimit . rlim_cur = filesLimit . rlim_max ;
SYSCHECK ( setrlimit ( RLIMIT_NOFILE , & filesLimit ), "setrlimit" );
return ncclSuccess ;
}
2024-09-10 05:57:10 -07:00
static ncclResult_t rootSend ( union ncclSocketAddress * addr , uint64_t magic , union ringConnectInfo * info ) {
ncclResult_t res = ncclSuccess ;
struct ncclSocket sock ;
NCCLCHECKGOTO ( ncclSocketInit ( & sock , addr , magic , ncclSocketTypeBootstrap ), res , fail );
NCCLCHECKGOTO ( ncclSocketConnect ( & sock ), res , fail );
NCCLCHECKGOTO ( socketSend ( & sock , info , sizeof ( union ringConnectInfo )), res , fail );
NCCLCHECK ( ncclSocketClose ( & sock ));
return res ;
fail :
( void ) ncclSocketClose ( & sock );
return res ;
}
static void * bootstrapRoot ( void * rargs ) {
uint64_t timers [ BOOTSTRAP_INIT_ROOT_N ] = { 0 };
2022-11-29 04:27:46 -08:00
struct bootstrapRootArgs * args = ( struct bootstrapRootArgs * ) rargs ;
struct ncclSocket * listenSock = args -> listenSock ;
uint64_t magic = args -> magic ;
2020-09-04 14:35:05 -07:00
ncclResult_t res = ncclSuccess ;
int nranks = 0 , c = 0 ;
2024-09-10 05:57:10 -07:00
int iroot = 0 , nroots = 0 , localId = 0 ;
int nrecv = 0 , n2send = 0 ;
2018-09-24 16:06:59 -07:00
struct extInfo info ;
2024-09-10 05:57:10 -07:00
union ringConnectInfo * rankInfo = NULL ;
union ncclSocketAddress * rankAddressesRoot = NULL ; // for initial rank <-> root information exchange
// get zeros for comparison
char zeroHandle [ NCCL_NET_HANDLE_MAXSIZE ];
union ncclSocketAddress zeroAddress ;
union ringConnectInfo zeroInfo ;
memset ( & zeroAddress , 0 , sizeof ( union ncclSocketAddress ));
memset ( & zeroHandle , 0 , NCCL_NET_HANDLE_MAXSIZE );
memset ( & zeroInfo , 0 , sizeof ( union ringConnectInfo ));
2018-09-24 16:06:59 -07:00
setFilesLimit ();
2024-09-10 05:57:10 -07:00
TRACE ( NCCL_BOOTSTRAP , "BEGIN" );
BOOTSTRAP_PROF_OPEN ( timers [ BOOTSTRAP_INIT_ROOT_WAIT ]);
2018-09-24 16:06:59 -07:00
/* Receive addresses from all ranks */
do {
2022-01-07 06:39:55 -08:00
struct ncclSocket sock ;
2022-11-29 04:27:46 -08:00
NCCLCHECKGOTO ( ncclSocketInit ( & sock ), res , out );
2022-01-07 06:39:55 -08:00
NCCLCHECKGOTO ( ncclSocketAccept ( & sock , listenSock ), res , out );
2024-09-10 05:57:10 -07:00
NCCLCHECKGOTO ( socketRecv ( & sock , & info , sizeof ( info )), res , out );
2022-11-29 04:27:46 -08:00
NCCLCHECKGOTO ( ncclSocketClose ( & sock ), res , out );
2018-10-24 14:44:59 -07:00
if ( c == 0 ) {
2024-09-10 05:57:10 -07:00
BOOTSTRAP_PROF_CLOSE ( timers [ BOOTSTRAP_INIT_ROOT_WAIT ]);
BOOTSTRAP_PROF_OPEN ( timers [ BOOTSTRAP_INIT_ROOT_RECV ]);
2018-09-24 16:06:59 -07:00
nranks = info . nranks ;
2024-09-10 05:57:10 -07:00
iroot = info . iroot ;
nroots = info . nroots ;
// if the number of root > 1, we will receive one extra info from the first local_id of the next root
n2send = nRankFromRoot ( iroot , nranks , nroots );
nrecv = n2send + (( nroots > 1 ) ? 1 : 0 );
NCCLCHECKGOTO ( ncclCalloc ( & rankInfo , nrecv * sizeof ( union ringConnectInfo )), res , out );
NCCLCHECKGOTO ( ncclCalloc ( & rankAddressesRoot , nrecv ), res , out );
2018-09-24 16:06:59 -07:00
}
2024-09-10 05:57:10 -07:00
if ( nranks != info . nranks || nroots != info . nroots || iroot != info . iroot ) {
WARN ( "Bootstrap Root : mismatch in info from procs, nranks %d vs %d, nroots %d vs %d, iroot %d vs %d" , nranks , info . nranks , nroots , info . nroots , iroot , info . iroot );
2018-09-24 16:06:59 -07:00
goto out ;
}
2024-09-10 05:57:10 -07:00
localId = localIdFromRoot ( info . rank , iroot , nranks , nroots );
if ( memcmp ( & zeroAddress , & rankAddressesRoot [ localId ], sizeof ( union ncclSocketAddress )) != 0 ||
memcmp ( & zeroInfo , & rankInfo [ localId ], sizeof ( union ringConnectInfo )) != 0 ) {
2018-10-24 14:44:59 -07:00
WARN ( "Bootstrap Root : rank %d of %d ranks has already checked in" , info . rank , nranks );
goto out ;
2018-09-24 16:06:59 -07:00
}
2024-09-10 05:57:10 -07:00
// if the previous has already checked in, send the newly received handle, if not save the handle for later
// if we have more than 1 root, I do not own the previous of local_id = 0
// if we have prev > n2send, we do not send anything
int prev = ( nroots > 1 ) ? ( localId - 1 ) : BOOTSTRAP_PID ( localId - 1 , nrecv );
if ( prev >= 0 && prev < n2send && memcmp ( & zeroAddress , & rankAddressesRoot [ prev ], sizeof ( union ncclSocketAddress )) != 0 ) {
NCCLCHECKGOTO ( rootSend ( & rankAddressesRoot [ prev ], magic , & info . connectInfo ), res , out );
} else {
memcpy ( & rankInfo [ localId ], & info . connectInfo , sizeof ( union ringConnectInfo ));
}
// if the next rank has checked in, send the newly received info, if not save the addr for later
// for nroots >=1, I will always own the information of the next connection
// if the local_id id must be [0 ; n2send[ otherwise we do not answer
int next = BOOTSTRAP_PID ( localId + 1 , nrecv );
if ( localId >= 0 && localId < n2send && memcmp ( & zeroInfo , & rankInfo [ next ], sizeof ( union ringConnectInfo )) != 0 ) {
NCCLCHECKGOTO ( rootSend ( & info . listenRootAddress , magic , & rankInfo [ next ]), res , out );
} else {
memcpy ( rankAddressesRoot + localId , & info . listenRootAddress , sizeof ( union ncclSocketAddress ));
}
2018-10-24 14:44:59 -07:00
++ c ;
2024-09-10 05:57:10 -07:00
TRACE ( NCCL_BOOTSTRAP , "Received connect from rank %d total %d/%d" , info . rank , c , nrecv );
} while ( c < nrecv );
TRACE ( NCCL_BOOTSTRAP , "COLLECTED ALL %d HANDLES" , nrecv );
BOOTSTRAP_PROF_CLOSE ( timers [ BOOTSTRAP_INIT_ROOT_RECV ]);
// send the remaining info to the ranks who haven't received anything
BOOTSTRAP_PROF_OPEN ( timers [ BOOTSTRAP_INIT_ROOT_SEND ]);
// here we need to send info only to my own local process
for ( int r = 0 ; r < n2send ; ++ r ) {
// use nrecv to periodize: if 1 root, we will send the first one to the last one, if >1 roots we will send the additional one we have received
int next = BOOTSTRAP_PID ( r + 1 , nrecv );
if ( memcmp ( & zeroAddress , & rankAddressesRoot [ r ], sizeof ( union ncclSocketAddress )) != 0 &&
memcmp ( & zeroInfo , & rankInfo [ next ], sizeof ( union ringConnectInfo )) != 0 ) {
NCCLCHECKGOTO ( rootSend ( & rankAddressesRoot [ r ], magic , & rankInfo [ next ]), res , out );
}
2018-10-24 14:44:59 -07:00
}
2024-09-10 05:57:10 -07:00
BOOTSTRAP_PROF_CLOSE ( timers [ BOOTSTRAP_INIT_ROOT_SEND ]);
TRACE ( NCCL_BOOTSTRAP | NCCL_PROFILE , "Root timings (wait %f, recv %f, send %f)" , timers [ BOOTSTRAP_INIT_ROOT_WAIT ] / 1e9 , timers [ BOOTSTRAP_INIT_ROOT_RECV ] / 1e9 , timers [ BOOTSTRAP_INIT_ROOT_SEND ] / 1e9 );
2018-09-24 16:06:59 -07:00
out :
2022-11-29 04:27:46 -08:00
if ( listenSock != NULL ) {
2024-09-10 05:57:10 -07:00
( void ) ncclSocketClose ( listenSock );
2022-11-29 04:27:46 -08:00
free ( listenSock );
}
2024-09-10 05:57:10 -07:00
if ( rankInfo )
free ( rankInfo );
if ( rankAddressesRoot )
free ( rankAddressesRoot );
2022-11-29 04:27:46 -08:00
free ( rargs );
2018-12-13 15:56:12 -08:00
2024-09-10 05:57:10 -07:00
TRACE ( NCCL_BOOTSTRAP , "DONE" );
2018-09-24 16:06:59 -07:00
return NULL ;
}
2022-11-29 04:27:46 -08:00
ncclResult_t bootstrapCreateRoot ( struct ncclBootstrapHandle * handle , bool idFromEnv ) {
2024-09-10 05:57:10 -07:00
ncclResult_t ret = ncclSuccess ;
struct ncclSocket * listenSock = NULL ;
struct bootstrapRootArgs * args = NULL ;
2022-11-29 04:27:46 -08:00
pthread_t thread ;
2022-01-07 06:39:55 -08:00
NCCLCHECK ( ncclCalloc ( & listenSock , 1 ));
2024-09-10 05:57:10 -07:00
NCCLCHECKGOTO ( ncclSocketInit ( listenSock , & handle -> addr , handle -> magic , ncclSocketTypeBootstrap , NULL , 0 ), ret , fail );
NCCLCHECKGOTO ( ncclSocketListen ( listenSock ), ret , fail );
NCCLCHECKGOTO ( ncclSocketGetAddr ( listenSock , & handle -> addr ), ret , fail );
2022-11-29 04:27:46 -08:00
2024-09-10 05:57:10 -07:00
NCCLCHECKGOTO ( ncclCalloc ( & args , 1 ), ret , fail );
2022-11-29 04:27:46 -08:00
args -> listenSock = listenSock ;
args -> magic = handle -> magic ;
2024-09-10 05:57:10 -07:00
PTHREADCHECKGOTO ( pthread_create ( & thread , NULL , bootstrapRoot , ( void * ) args ), "pthread_create" , ret , fail );
2022-01-07 06:39:55 -08:00
ncclSetThreadName ( thread , "NCCL BootstrapR" );
2024-09-10 05:57:10 -07:00
PTHREADCHECKGOTO ( pthread_detach ( thread ), "pthread_detach" , ret , fail ); // will not be pthread_join()'d
exit :
return ret ;
fail :
if ( listenSock ) free ( listenSock );
if ( args ) free ( args );
goto exit ;
2018-09-24 16:06:59 -07:00
}
2022-11-29 04:27:46 -08:00
ncclResult_t bootstrapGetUniqueId ( struct ncclBootstrapHandle * handle ) {
memset ( handle , 0 , sizeof ( ncclBootstrapHandle ));
2018-09-24 16:06:59 -07:00
2023-09-26 05:47:28 -07:00
const char * env = ncclGetEnv ( "NCCL_COMM_ID" );
2018-09-24 16:06:59 -07:00
if ( env ) {
2020-05-12 14:40:18 -07:00
INFO ( NCCL_ENV , "NCCL_COMM_ID set by environment to %s" , env );
2022-11-29 04:27:46 -08:00
if ( ncclSocketGetAddrFromString ( & handle -> addr , env ) != ncclSuccess ) {
2018-09-24 16:06:59 -07:00
WARN ( "Invalid NCCL_COMM_ID, please use format: <ipv4>:<port> or [<ipv6>]:<port> or <hostname>:<port>" );
return ncclInvalidArgument ;
}
2024-06-11 01:28:01 -07:00
handle -> magic = NCCL_MAGIC ;
2018-09-24 16:06:59 -07:00
} else {
2024-06-11 01:28:01 -07:00
NCCLCHECK ( getRandomData ( & handle -> magic , sizeof ( handle -> magic )));
2022-11-29 04:27:46 -08:00
memcpy ( & handle -> addr , & bootstrapNetIfAddr , sizeof ( union ncclSocketAddress ));
NCCLCHECK ( bootstrapCreateRoot ( handle , false ));
2018-09-24 16:06:59 -07:00
}
return ncclSuccess ;
}
2018-12-13 15:56:12 -08:00
struct unexConn {
int peer ;
2021-04-12 16:00:11 -07:00
int tag ;
2022-01-07 06:39:55 -08:00
struct ncclSocket sock ;
2018-12-13 15:56:12 -08:00
struct unexConn * next ;
};
2024-09-10 05:57:10 -07:00
struct bootstrapRing_t {
union {
struct {
void * sendComm , * recvComm ;
ncclNetDeviceHandle_t * sendDevHandle , * recvDevHandle ;
} net ;
struct {
struct ncclSocket recv ;
struct ncclSocket send ;
} socket ;
};
};
struct bootstrapListen_t {
struct ncclSocket peerSocket ; // socket for peers to contact me in P2P
union {
struct {
int dev ;
void * comm ;
char handle [ NCCL_NET_HANDLE_MAXSIZE ];
} net ;
struct ncclSocket socket ; // socket to be used for the ring
};
};
2022-01-07 06:39:55 -08:00
struct bootstrapState {
2024-09-10 05:57:10 -07:00
struct bootstrapRing_t ring ;
struct bootstrapListen_t listen ;
ncclNet_t * net ;
2024-02-05 05:06:02 -08:00
uint64_t * peerProxyAddressesUDS ;
2024-09-10 05:57:10 -07:00
union ncclSocketAddress * peerProxyAddresses ;
union ncclSocketAddress * peerP2pAddresses ;
2018-12-13 15:56:12 -08:00
struct unexConn * unexpectedConnections ;
2020-09-04 14:35:05 -07:00
int cudaDev ;
2018-09-24 16:06:59 -07:00
int rank ;
int nranks ;
2022-11-29 04:27:46 -08:00
uint64_t magic ;
2024-09-10 05:57:10 -07:00
volatile uint32_t * abortFlag ;
2018-09-24 16:06:59 -07:00
};
2024-09-10 05:57:10 -07:00
#define STATE_RING(s, f) (s->ring.f)
#define STATE_LISTEN(s, f) (s->listen.f)
// helper functions
static ncclResult_t createListenSocket ( struct ncclComm * comm , uint64_t magic , struct ncclSocket * socket , union ncclSocketAddress * addr ,
ncclSocketType type ) {
NCCLCHECK ( ncclSocketInit ( socket , & bootstrapNetIfAddr , magic , type , comm -> abortFlag ));
NCCLCHECK ( ncclSocketListen ( socket ));
NCCLCHECK ( ncclSocketGetAddr ( socket , addr ));
return ncclSuccess ;
}
static ncclResult_t getUDS ( uint64_t * peerUDS ) {
uint64_t randId ;
NCCLCHECK ( getRandomData ( & randId , sizeof ( randId )));
* peerUDS = getPidHash () + randId ;
return ncclSuccess ;
}
#define MAX_OOB_DEVS 16
static ncclResult_t netGetDevice ( int rank , struct ncclComm * comm , int * dev ) {
static int devOOB = - 1 ;
if ( devOOB < 0 ) {
pthread_mutex_lock ( & bootstrapNetLock );
if ( devOOB < 0 ) {
char * userIfEnv = getenv ( "NCCL_OOB_NET_IFNAME" );
if ( userIfEnv && strlen ( userIfEnv ) > 0 ) {
INFO ( NCCL_BOOTSTRAP | NCCL_ENV , "NCCL_OOB_NET_IFNAME set to %s" , userIfEnv );
bool searchNot = userIfEnv && userIfEnv [ 0 ] == '^' ;
if ( searchNot ) userIfEnv ++ ;
bool searchExact = userIfEnv && userIfEnv [ 0 ] == '=' ;
if ( searchExact ) userIfEnv ++ ;
struct netIf userIfs [ MAX_OOB_DEVS ];
int nUserIfs = parseStringList ( userIfEnv , userIfs , MAX_OOB_DEVS );
// loop over the device and return the first one matching
int devId = 0 ;
int nDev = 0 ;
NCCLCHECK ( comm -> ncclNet -> devices ( & nDev ));
while ( devId < nDev ) {
ncclNetProperties_t props ;
comm -> ncclNet -> getProperties ( devId , & props );
// check against user specified HCAs/ports
bool found = matchIfList ( props . name , props . port , userIfs , nUserIfs , searchExact ) ^ searchNot ;
if ( found ) {
devOOB = devId ;
break ;
}
devId ++ ;
}
if ( devOOB == - 1 ) {
WARN ( "no device found matching NCCL_OOB_NET_IFNAME=%s, ignoring" , userIfEnv );
goto noEnv ;
}
} else {
noEnv :
// default choice is device 0
devOOB = 0 ;
}
}
pthread_mutex_unlock ( & bootstrapNetLock );
}
* dev = devOOB ;
return ncclSuccess ;
}
static ncclResult_t netRingConnect ( ncclNet_t * net , struct bootstrapListen_t * listen , char peerHandle [ NCCL_NET_HANDLE_MAXSIZE ],
void ** sendComm , ncclNetDeviceHandle_t ** sendDevHandle ,
void ** recvComm , ncclNetDeviceHandle_t ** recvDevHandle , volatile uint32_t * abortFlag ) {
2018-09-24 16:06:59 -07:00
2024-09-10 05:57:10 -07:00
int abortCounter = 0 ;
do {
NCCLCHECK ( checkAbort ( abortFlag , & abortCounter ));
if ( !* sendComm )
NCCLCHECK ( net -> connect ( listen -> net . dev , peerHandle , sendComm , sendDevHandle ));
if ( !* recvComm )
NCCLCHECK ( net -> accept ( listen -> net . comm , recvComm , recvDevHandle ));
} while ( !* sendComm || !* recvComm );
return ncclSuccess ;
}
static ncclResult_t socketRingConnect ( ncclSocketAddress * addr , struct ncclSocket * sendSocket , struct ncclSocket * listenSock , struct ncclSocket * recvSocket , uint64_t magic , volatile uint32_t * abortFlag ) {
NCCLCHECK ( ncclSocketInit ( sendSocket , addr , magic , ncclSocketTypeBootstrap , abortFlag ));
NCCLCHECK ( ncclSocketConnect ( sendSocket ));
NCCLCHECK ( ncclSocketInit ( recvSocket ));
NCCLCHECK ( ncclSocketAccept ( recvSocket , listenSock ));
return ncclSuccess ;
}
static ncclResult_t ringAllInfo ( struct ncclComm * comm , struct bootstrapState * state ,
union ncclSocketAddress * peerAddresss ,
union ncclSocketAddress * peerProxy , uint64_t * peerUDS ) {
ncclResult_t res = ncclSuccess ;
int rank = comm -> rank ;
int nRanks = comm -> nRanks ;
struct bootstrapRingData {
union ncclSocketAddress peerAddress ;
union ncclSocketAddress peerProxy ;
uint64_t peerUDS ;
} * ringData = NULL ;
NCCLCHECK ( ncclCalloc ( & ringData , nRanks ));
// pack
if ( peerAddresss )
memcpy ( & ( ringData [ rank ]. peerAddress ), peerAddresss + rank , sizeof ( union ncclSocketAddress ));
if ( peerProxy )
memcpy ( & ( ringData [ rank ]. peerProxy ), peerProxy + rank , sizeof ( union ncclSocketAddress ));
if ( peerUDS )
memcpy ( & ( ringData [ rank ]. peerUDS ), peerUDS + rank , sizeof ( uint64_t ));
// allgather
NCCLCHECKGOTO ( bootstrapAllGather ( state , ringData , sizeof ( struct bootstrapRingData )), res , exit );
// unpack
for ( int irank = 0 ; irank < nRanks ; ++ irank ) {
if ( peerAddresss )
memcpy ( peerAddresss + irank , & ( ringData [ irank ]. peerAddress ), sizeof ( union ncclSocketAddress ));
if ( peerProxy )
memcpy ( peerProxy + irank , & ( ringData [ irank ]. peerProxy ), sizeof ( union ncclSocketAddress ));
if ( peerUDS )
memcpy ( peerUDS + irank , & ( ringData [ irank ]. peerUDS ), sizeof ( uint64_t ));
}
exit :
free ( ringData );
return ncclSuccess ;
}
static ncclResult_t sendToRoot ( struct ncclBootstrapHandle * handle , struct ncclComm * comm , struct extInfo * info ) {
ncclResult_t ret = ncclSuccess ;
struct ncclSocket sock ;
NCCLCHECK ( ncclSocketInit ( & sock , & handle -> addr , handle -> magic , ncclSocketTypeBootstrap , comm -> abortFlag ));
NCCLCHECKGOTO ( ncclSocketConnect ( & sock ), ret , fail );
NCCLCHECKGOTO ( socketSend ( & sock , info , sizeof ( struct extInfo )), ret , fail );
NCCLCHECK ( ncclSocketClose ( & sock ));
return ret ;
fail :
( void ) ncclSocketClose ( & sock );
return ret ;
}
NCCL_PARAM ( StaggerRate , "UID_STAGGER_RATE" , 7000 );
NCCL_PARAM ( StaggerThreshold , "UID_STAGGER_THRESHOLD" , 256 );
ncclResult_t bootstrapInit ( int nHandles , void * handles , struct ncclComm * comm ) {
2022-01-07 06:39:55 -08:00
int rank = comm -> rank ;
int nranks = comm -> nRanks ;
2024-09-10 05:57:10 -07:00
// char nextPeerHandle[NCCL_NET_HANDLE_MAXSIZE];
2022-01-07 06:39:55 -08:00
struct bootstrapState * state ;
2022-11-29 04:27:46 -08:00
struct ncclSocket * proxySocket ;
struct ncclSocket sock , listenSockRoot ;
2024-09-10 05:57:10 -07:00
struct extInfo info = { 0 };
union ringConnectInfo nextPeer ;
uint64_t timers [ BOOTSTRAP_INIT_TIME_N ] = { 0 };
2022-11-29 04:27:46 -08:00
2018-09-24 16:06:59 -07:00
NCCLCHECK ( ncclCalloc ( & state , 1 ));
state -> rank = rank ;
state -> nranks = nranks ;
2024-09-10 05:57:10 -07:00
state -> cudaDev = comm -> cudaDev ;
2022-01-07 06:39:55 -08:00
state -> abortFlag = comm -> abortFlag ;
2024-09-10 05:57:10 -07:00
state -> net = comm -> ncclNet ;
2022-01-07 06:39:55 -08:00
comm -> bootstrap = state ;
2024-09-10 05:57:10 -07:00
comm -> magic = state -> magic = BOOTSTRAP_HANDLE ( handles , 0 ) -> magic ; // state and comm magic set to the first magic ID
2018-12-13 15:56:12 -08:00
2024-09-10 05:57:10 -07:00
TRACE ( NCCL_BOOTSTRAP , "rank %d nranks %d" , rank , nranks );
2018-09-24 16:06:59 -07:00
2024-09-10 05:57:10 -07:00
BOOTSTRAP_PROF_OPEN ( timers [ BOOTSTRAP_INIT_TIME_TOTAL ]);
// fill up the info
2018-09-24 16:06:59 -07:00
info . nranks = nranks ;
2024-09-10 05:57:10 -07:00
info . nroots = nHandles ;
// get the ring connection info
memset ( & nextPeer , 0 , sizeof ( union ringConnectInfo ));
BOOTSTRAP_PROF_OPEN ( timers [ BOOTSTRAP_INIT_TIME_CREATE ]);
if ( ncclParamBootstrapNetEnable ()) {
// Create net interface for other ranks to contact me (all gather)
NCCLCHECK ( netGetDevice ( rank , comm , & STATE_LISTEN ( state , net . dev )));
NCCLCHECK ( state -> net -> listen ( STATE_LISTEN ( state , net . dev ), STATE_LISTEN ( state , net . handle ), & STATE_LISTEN ( state , net . comm )));
memcpy ( info . connectInfo . handle , STATE_LISTEN ( state , net . handle ), NCCL_NET_HANDLE_MAXSIZE );
} else {
// create socket for ring neightbor to contact mee
NCCLCHECK ( createListenSocket ( comm , comm -> magic , & STATE_LISTEN ( state , socket ), & info . connectInfo . addr , ncclSocketTypeBootstrap ));
}
// Create socket for root to contact me using the root's magic
int curr_root = rootIdFromRank ( rank , nranks , nHandles );
NCCLCHECK ( createListenSocket ( comm , BOOTSTRAP_HANDLE ( handles , curr_root ) -> magic , & listenSockRoot , & info . listenRootAddress , ncclSocketTypeBootstrap ));
BOOTSTRAP_PROF_CLOSE ( timers [ BOOTSTRAP_INIT_TIME_CREATE ]);
2020-09-04 14:35:05 -07:00
// stagger connection times to avoid an overload of the root
2024-09-10 05:57:10 -07:00
BOOTSTRAP_PROF_OPEN ( timers [ BOOTSTRAP_INIT_TIME_DELAY ]);
int nRankRoot = nRankFromRoot ( curr_root , nranks , nHandles );
if ( nRankRoot > ncclParamStaggerThreshold ()) {
// for socket the message rate in microsec
double msg_rate = ncclParamStaggerRate () / 1.0e6 ;
long musec = localIdFromRoot ( rank , curr_root , nranks , nHandles ) / msg_rate ;
2018-12-13 15:56:12 -08:00
struct timespec tv ;
2024-09-10 05:57:10 -07:00
long c_1e6 = 1e6 ;
tv . tv_sec = musec / c_1e6 ;
tv . tv_nsec = 1e3 * ( musec % c_1e6 );
TRACE ( NCCL_BOOTSTRAP , "rank %d delaying connection to root by %ld microsec" , rank , musec );
( void ) nanosleep ( & tv , NULL );
2018-12-13 15:56:12 -08:00
}
2024-09-10 05:57:10 -07:00
BOOTSTRAP_PROF_CLOSE ( timers [ BOOTSTRAP_INIT_TIME_DELAY ]);
2018-10-24 14:44:59 -07:00
2018-12-13 15:56:12 -08:00
// send info on my listening socket to root
2024-09-10 05:57:10 -07:00
BOOTSTRAP_PROF_OPEN ( timers [ BOOTSTRAP_INIT_TIME_SEND ]);
// send contact info to my own root
info . rank = rank ;
info . iroot = curr_root ;
NCCLCHECK ( sendToRoot ( BOOTSTRAP_HANDLE ( handles , curr_root ), comm , & info ));
// if needed, send the connection info to the previous root
if ( nHandles > 1 && isFirstFromRoot ( rank , curr_root , nranks , nHandles )) {
int prev_rank = BOOTSTRAP_PID ( rank - 1 , nranks );
int prev_root = rootIdFromRank ( prev_rank , nranks , nHandles );
info . rank = prev_rank + 1 ; // my rank as seen by the previous root
info . iroot = prev_root ;
NCCLCHECK ( sendToRoot ( BOOTSTRAP_HANDLE ( handles , prev_root ), comm , & info ));
}
BOOTSTRAP_PROF_CLOSE ( timers [ BOOTSTRAP_INIT_TIME_SEND ]);
2018-10-24 14:44:59 -07:00
// get info on my "next" rank in the bootstrap ring from root
2024-09-10 05:57:10 -07:00
BOOTSTRAP_PROF_OPEN ( timers [ BOOTSTRAP_INIT_TIME_RECV ]);
2022-11-29 04:27:46 -08:00
NCCLCHECK ( ncclSocketInit ( & sock ));
2022-01-07 06:39:55 -08:00
NCCLCHECK ( ncclSocketAccept ( & sock , & listenSockRoot ));
2024-09-10 05:57:10 -07:00
NCCLCHECK ( socketRecv ( & sock , & nextPeer , sizeof ( nextPeer )));
2022-11-29 04:27:46 -08:00
NCCLCHECK ( ncclSocketClose ( & sock ));
NCCLCHECK ( ncclSocketClose ( & listenSockRoot ));
2024-09-10 05:57:10 -07:00
BOOTSTRAP_PROF_CLOSE ( timers [ BOOTSTRAP_INIT_TIME_RECV ]);
2018-10-24 14:44:59 -07:00
2024-09-10 05:57:10 -07:00
// accept and connect the ring network
if ( ncclParamBootstrapNetEnable ()) {
NCCLCHECK ( netRingConnect ( state -> net , & state -> listen , nextPeer . handle ,
& STATE_RING ( state , net . sendComm ), & STATE_RING ( state , net . sendDevHandle ),
& STATE_RING ( state , net . recvComm ), & STATE_RING ( state , net . recvDevHandle ), state -> abortFlag ));
} else {
NCCLCHECK ( socketRingConnect ( & nextPeer . addr , & STATE_RING ( state , socket . send ), & STATE_LISTEN ( state , socket ), & STATE_RING ( state , socket . recv ), comm -> magic , state -> abortFlag ));
}
2018-12-13 15:56:12 -08:00
// AllGather all listen handlers
2024-09-10 05:57:10 -07:00
// in case of failure, those resources will be free'd when calling bootstrapDestroy, so we can return immediatly
2022-01-07 06:39:55 -08:00
NCCLCHECK ( ncclCalloc ( & state -> peerProxyAddresses , nranks ));
2024-09-10 05:57:10 -07:00
NCCLCHECK ( ncclCalloc ( & proxySocket , 1 ));
NCCLCHECK ( createListenSocket ( comm , comm -> magic , proxySocket , state -> peerProxyAddresses + rank , ncclSocketTypeProxy ));
2024-02-05 05:06:02 -08:00
NCCLCHECK ( ncclCalloc ( & state -> peerProxyAddressesUDS , nranks ));
2024-09-10 05:57:10 -07:00
NCCLCHECK ( getUDS ( state -> peerProxyAddressesUDS + rank ));
2022-11-29 04:27:46 -08:00
2024-09-10 05:57:10 -07:00
// create a socket for others to reach out (P2P)
union ncclSocketAddress peerSocketAddress ;
NCCLCHECK ( createListenSocket ( comm , comm -> magic , & STATE_LISTEN ( state , peerSocket ), & peerSocketAddress , ncclSocketTypeBootstrap ));
NCCLCHECK ( ncclCalloc ( & state -> peerP2pAddresses , nranks * sizeof ( union ncclSocketAddress )));
memcpy ( state -> peerP2pAddresses + rank , & peerSocketAddress , sizeof ( union ncclSocketAddress ));
BOOTSTRAP_PROF_OPEN ( timers [ BOOTSTRAP_INIT_TIME_RING ]);
NCCLCHECK ( ringAllInfo ( comm , state , state -> peerP2pAddresses , state -> peerProxyAddresses , state -> peerProxyAddressesUDS ));
BOOTSTRAP_PROF_CLOSE ( timers [ BOOTSTRAP_INIT_TIME_RING ]);
// Create the service proxy and get the UDS
2024-02-05 05:06:02 -08:00
NCCLCHECK ( ncclProxyInit ( comm , proxySocket , state -> peerProxyAddresses , state -> peerProxyAddressesUDS ));
2018-12-13 15:56:12 -08:00
2024-09-10 05:57:10 -07:00
BOOTSTRAP_PROF_CLOSE ( timers [ BOOTSTRAP_INIT_TIME_TOTAL ]);
TRACE ( NCCL_BOOTSTRAP , "rank %d nranks %d - DONE" , rank , nranks );
INFO ( NCCL_BOOTSTRAP | NCCL_PROFILE , "Bootstrap timings total %f (create %f, send %f, recv %f, ring %f, delay %f)" , timers [ BOOTSTRAP_INIT_TIME_TOTAL ] / 1e9 ,
timers [ BOOTSTRAP_INIT_TIME_CREATE ] / 1e9 ,
timers [ BOOTSTRAP_INIT_TIME_SEND ] / 1e9 ,
timers [ BOOTSTRAP_INIT_TIME_RECV ] / 1e9 ,
timers [ BOOTSTRAP_INIT_TIME_RING ] / 1e9 ,
timers [ BOOTSTRAP_INIT_TIME_DELAY ] / 1e9 );
2018-09-24 16:06:59 -07:00
return ncclSuccess ;
}
2024-09-10 05:57:10 -07:00
ncclResult_t bootstrapSplit ( uint64_t magic , struct ncclComm * comm , struct ncclComm * parent , int color , int key , int * parentRanks ) {
2023-04-03 05:32:07 -07:00
ncclResult_t ret = ncclSuccess ;
int rank = comm -> rank ;
int nranks = comm -> nRanks ;
int prev , next ;
2024-09-10 05:57:10 -07:00
union ringConnectInfo info ;
union ringConnectInfo nextPeer ;
struct ncclSocket * proxySocket = NULL ;
2023-04-03 05:32:07 -07:00
struct bootstrapState * state ;
NCCLCHECKGOTO ( ncclCalloc ( & state , 1 ), ret , fail );
state -> rank = rank ;
state -> nranks = nranks ;
2024-09-10 05:57:10 -07:00
state -> cudaDev = comm -> cudaDev ;
2023-04-03 05:32:07 -07:00
state -> abortFlag = comm -> abortFlag ;
2024-09-10 05:57:10 -07:00
state -> net = comm -> ncclNet ;
2023-04-03 05:32:07 -07:00
comm -> bootstrap = state ;
2024-09-10 05:57:10 -07:00
comm -> magic = state -> magic = magic ;
2023-04-03 05:32:07 -07:00
2024-09-10 05:57:10 -07:00
prev = parentRanks [( rank - 1 + nranks ) % nranks ];
next = parentRanks [( rank + 1 ) % nranks ];
2023-04-03 05:32:07 -07:00
2024-09-10 05:57:10 -07:00
// create a handle for the others to reach out to me
if ( ncclParamBootstrapNetEnable ()) {
NCCLCHECKGOTO ( netGetDevice ( rank , comm , & STATE_LISTEN ( state , net . dev )), ret , fail );
NCCLCHECKGOTO ( state -> net -> listen ( STATE_LISTEN ( state , net . dev ), STATE_LISTEN ( state , net . handle ), & STATE_LISTEN ( state , net . comm )), ret , fail );
memcpy ( info . handle , STATE_LISTEN ( state , net . handle ), NCCL_NET_HANDLE_MAXSIZE );
} else {
// create socket for ring neightbor to contact mee
NCCLCHECK ( createListenSocket ( comm , comm -> magic , & STATE_LISTEN ( state , socket ), & info . addr , ncclSocketTypeBootstrap ));
}
// create a socket for others to reach out (P2P)
union ncclSocketAddress peerSocketAddress ;
NCCLCHECK ( createListenSocket ( comm , comm -> magic , & STATE_LISTEN ( state , peerSocket ), & peerSocketAddress , ncclSocketTypeBootstrap ));
// Get addr from next rank using the parent's connections
NCCLCHECKGOTO ( bootstrapSend ( parent -> bootstrap , prev , BOOTSTRAP_TAG_COMMSPLIT , & info , sizeof ( union ringConnectInfo )), ret , fail );
NCCLCHECKGOTO ( bootstrapRecv ( parent -> bootstrap , next , BOOTSTRAP_TAG_COMMSPLIT , & nextPeer , sizeof ( union ringConnectInfo )), ret , fail );
if ( ncclParamBootstrapNetEnable ()) {
NCCLCHECKGOTO ( netRingConnect ( state -> net , & state -> listen , nextPeer . handle ,
& STATE_RING ( state , net . sendComm ), & STATE_RING ( state , net . sendDevHandle ),
& STATE_RING ( state , net . recvComm ), & STATE_RING ( state , net . recvDevHandle ), state -> abortFlag ),
ret , fail );
} else {
NCCLCHECK ( socketRingConnect ( & nextPeer . addr , & STATE_RING ( state , socket . send ), & STATE_LISTEN ( state , socket ), & STATE_RING ( state , socket . recv ), comm -> magic , state -> abortFlag ));
}
2023-04-03 05:32:07 -07:00
2024-09-10 05:57:10 -07:00
NCCLCHECKGOTO ( ncclCalloc ( & state -> peerP2pAddresses , nranks * sizeof ( union ncclSocketAddress )), ret , fail );
memcpy ( state -> peerP2pAddresses + rank , & peerSocketAddress , sizeof ( union ncclSocketAddress ));
2023-04-03 05:32:07 -07:00
if ( parent -> config . splitShare ) {
/* map local rank to top parent local rank. */
for ( int i = 0 ; i < nranks ; ++ i ) {
comm -> topParentRanks [ i ] = parent -> topParentRanks [ parentRanks [ i ]];
}
2024-09-10 05:57:10 -07:00
NCCLCHECKGOTO ( ringAllInfo ( comm , state , state -> peerP2pAddresses , NULL , NULL ), ret , fail );
2023-04-03 05:32:07 -07:00
} else {
NCCLCHECKGOTO ( ncclCalloc ( & state -> peerProxyAddresses , nranks ), ret , fail );
2024-02-05 05:06:02 -08:00
NCCLCHECKGOTO ( ncclCalloc ( & state -> peerProxyAddressesUDS , nranks ), ret , fail );
2024-09-10 05:57:10 -07:00
// Create the service proxy and get the UDS
NCCLCHECKGOTO ( ncclCalloc ( & proxySocket , 1 ), ret , fail );
NCCLCHECKGOTO ( getUDS ( state -> peerProxyAddressesUDS + rank ), ret , fail );
NCCLCHECKGOTO ( createListenSocket ( comm , comm -> magic , proxySocket , state -> peerProxyAddresses + rank , ncclSocketTypeProxy ), ret , fail );
NCCLCHECKGOTO ( ringAllInfo ( comm , state , state -> peerP2pAddresses , state -> peerProxyAddresses , state -> peerProxyAddressesUDS ), ret , fail );
2024-02-05 05:06:02 -08:00
NCCLCHECKGOTO ( ncclProxyInit ( comm , proxySocket , state -> peerProxyAddresses , state -> peerProxyAddressesUDS ), ret , fail );
2023-04-03 05:32:07 -07:00
}
2024-09-10 05:57:10 -07:00
TRACE ( NCCL_BOOTSTRAP , "bootstrapSplit: comm %p parent %p rank %d nranks %d color %d key %d prev %d next %d - DONE" , comm , parent , rank , nranks ,
color , key , prev , next );
2023-04-03 05:32:07 -07:00
exit :
return ret ;
fail :
2024-09-10 05:57:10 -07:00
free ( proxySocket );
2023-04-03 05:32:07 -07:00
goto exit ;
}
2024-09-10 05:57:10 -07:00
struct socketAckInfo {
int rank ;
int tag ;
};
static ncclResult_t socketConnect ( void * commState , int peer , int tag , struct ncclSocket * sock ) {
2024-03-26 06:08:55 -07:00
ncclResult_t ret = ncclSuccess ;
struct bootstrapState * state = ( struct bootstrapState * ) commState ;
2018-09-24 16:06:59 -07:00
2024-09-10 05:57:10 -07:00
struct socketAckInfo ack = ( struct socketAckInfo ){. rank = state -> rank , . tag = tag };
NCCLCHECKGOTO ( ncclSocketInit ( sock , state -> peerP2pAddresses + peer , state -> magic , ncclSocketTypeBootstrap ), ret , fail );
2024-03-26 06:08:55 -07:00
NCCLCHECKGOTO ( ncclSocketConnect ( sock ), ret , fail );
2024-09-10 05:57:10 -07:00
NCCLCHECKGOTO ( socketSend ( sock , & ack , sizeof ( struct socketAckInfo )), ret , fail );
2018-09-24 16:06:59 -07:00
return ncclSuccess ;
2024-03-26 06:08:55 -07:00
fail :
2024-09-10 05:57:10 -07:00
( void ) ncclSocketClose ( sock );
2024-03-26 06:08:55 -07:00
return ret ;
2018-09-24 16:06:59 -07:00
}
2021-04-12 16:00:11 -07:00
ncclResult_t bootstrapSend ( void * commState , int peer , int tag , void * data , int size ) {
2022-11-29 04:27:46 -08:00
ncclResult_t ret = ncclSuccess ;
2022-01-07 06:39:55 -08:00
struct ncclSocket sock ;
2024-03-26 06:08:55 -07:00
TRACE ( NCCL_BOOTSTRAP , "Sending to peer=%d tag=%d size=%d" , peer , tag , size );
2024-09-10 05:57:10 -07:00
NCCLCHECK ( socketConnect ( commState , peer , tag , & sock ));
NCCLCHECKGOTO ( socketSend ( & sock , data , size ), ret , fail );
2024-03-26 06:08:55 -07:00
TRACE ( NCCL_BOOTSTRAP , "Sent to peer=%d tag=%d size=%d" , peer , tag , size );
2022-11-29 04:27:46 -08:00
NCCLCHECK ( ncclSocketClose ( & sock ));
return ret ;
2024-09-10 05:57:10 -07:00
fail :
( void ) ncclSocketClose ( & sock );
return ret ;
2023-02-27 02:48:21 -08:00
}
2024-09-10 05:57:10 -07:00
// Bootstrap send/receive functions
static ncclResult_t unexpectedEnqueue ( struct bootstrapState * state , int peer , int tag , struct ncclSocket * sock ) {
2018-12-13 15:56:12 -08:00
// New unex
struct unexConn * unex ;
NCCLCHECK ( ncclCalloc ( & unex , 1 ));
unex -> peer = peer ;
2021-04-12 16:00:11 -07:00
unex -> tag = tag ;
2022-01-07 06:39:55 -08:00
memcpy ( & unex -> sock , sock , sizeof ( struct ncclSocket ));
2018-12-13 15:56:12 -08:00
// Enqueue
struct unexConn * list = state -> unexpectedConnections ;
if ( list == NULL ) {
state -> unexpectedConnections = unex ;
return ncclSuccess ;
}
while ( list -> next ) list = list -> next ;
list -> next = unex ;
return ncclSuccess ;
}
2024-09-10 05:57:10 -07:00
static ncclResult_t unexpectedDequeue ( struct bootstrapState * state , int peer , int tag , struct ncclSocket * sock , int * found ) {
2018-12-13 15:56:12 -08:00
struct unexConn * elem = state -> unexpectedConnections ;
struct unexConn * prev = NULL ;
2022-11-29 04:27:46 -08:00
* found = 0 ;
2018-12-13 15:56:12 -08:00
while ( elem ) {
2021-04-12 16:00:11 -07:00
if ( elem -> peer == peer && elem -> tag == tag ) {
2018-12-13 15:56:12 -08:00
if ( prev == NULL ) {
state -> unexpectedConnections = elem -> next ;
} else {
prev -> next = elem -> next ;
}
2022-01-07 06:39:55 -08:00
memcpy ( sock , & elem -> sock , sizeof ( struct ncclSocket ));
2018-12-13 15:56:12 -08:00
free ( elem );
2022-11-29 04:27:46 -08:00
* found = 1 ;
2022-01-07 06:39:55 -08:00
return ncclSuccess ;
2018-12-13 15:56:12 -08:00
}
prev = elem ;
elem = elem -> next ;
}
2022-01-07 06:39:55 -08:00
return ncclSuccess ;
2018-12-13 15:56:12 -08:00
}
2022-11-29 04:27:46 -08:00
static void unexpectedFree ( struct bootstrapState * state ) {
struct unexConn * elem = state -> unexpectedConnections ;
struct unexConn * prev = NULL ;
while ( elem ) {
prev = elem ;
elem = elem -> next ;
free ( prev );
}
return ;
}
2018-12-13 15:56:12 -08:00
// We can't know who we'll receive from, so we need to receive everything at once
2024-09-10 05:57:10 -07:00
static ncclResult_t socketAccept ( void * commState , int peer , int tag , struct ncclSocket * sock ) {
2022-11-29 04:27:46 -08:00
ncclResult_t ret = ncclSuccess ;
2022-01-07 06:39:55 -08:00
struct bootstrapState * state = ( struct bootstrapState * ) commState ;
2018-12-13 15:56:12 -08:00
// Search unexpected connections first
2022-11-29 04:27:46 -08:00
int found ;
2024-03-26 06:08:55 -07:00
NCCLCHECK ( unexpectedDequeue ( state , peer , tag , sock , & found ));
if ( found ) return ncclSuccess ;
2018-12-13 15:56:12 -08:00
// Then look for new connections
while ( 1 ) {
2024-09-10 05:57:10 -07:00
struct socketAckInfo ack = { 0 };
2024-03-26 06:08:55 -07:00
NCCLCHECKGOTO ( ncclSocketInit ( sock ), ret , fail );
2024-09-10 05:57:10 -07:00
NCCLCHECKGOTO ( ncclSocketAccept ( sock , & STATE_LISTEN ( state , peerSocket )), ret , fail );
NCCLCHECKGOTO ( socketRecv ( sock , & ack , sizeof ( struct socketAckInfo )), ret , fail );
if ( ack . rank == peer && ack . tag == tag ) return ncclSuccess ;
NCCLCHECKGOTO ( unexpectedEnqueue ( state , ack . rank , ack . tag , sock ), ret , fail );
2018-12-13 15:56:12 -08:00
}
2024-03-26 06:08:55 -07:00
return ncclSuccess ;
fail :
2024-09-10 05:57:10 -07:00
( void ) ncclSocketClose ( sock );
2024-03-26 06:08:55 -07:00
return ret ;
}
// We can't know who we'll receive from, so we need to receive everything at once
ncclResult_t bootstrapRecv ( void * commState , int peer , int tag , void * data , int size ) {
ncclResult_t ret ;
struct ncclSocket sock ;
2024-09-10 05:57:10 -07:00
NCCLCHECK ( socketAccept ( commState , peer , tag , & sock ));
2024-03-26 06:08:55 -07:00
TRACE ( NCCL_BOOTSTRAP , "Receiving tag=%d peer=%d size=%d" , tag , peer , size );
2024-09-10 05:57:10 -07:00
NCCLCHECKGOTO ( socketRecv ( & sock , (( char * ) data ), size ), ret , fail );
2022-11-29 04:27:46 -08:00
NCCLCHECK ( ncclSocketClose ( & sock ));
return ret ;
2024-09-10 05:57:10 -07:00
fail :
( void ) ncclSocketClose ( & sock );
return ret ;
2024-03-26 06:08:55 -07:00
}
2024-09-10 05:57:10 -07:00
static ncclResult_t netRingAllGather ( ncclNet_t * net , void * sendComm , void * recvComm , int rank , int nranks , char * data , int size , volatile uint32_t * abortFlag ) {
ncclResult_t res ;
uint64_t tFirst = 0 , tRest = 0 ;
void * sendDataHandle = NULL ;
void * recvDataHandle = NULL ;
NCCLCHECKGOTO ( netReg ( net , sendComm , data , nranks * size , & sendDataHandle ), res , exit );
NCCLCHECKGOTO ( netReg ( net , recvComm , data , nranks * size , & recvDataHandle ), res , exit );
2024-03-26 06:08:55 -07:00
/* Simple ring based AllGather
* At each step i receive data from (rank-i-1) from prev
* and send previous step's data from (rank-i) to next
*/
2024-09-10 05:57:10 -07:00
TRACE ( NCCL_BOOTSTRAP , "NetRingAllGather started" );
BOOTSTRAP_PROF_OPEN ( tFirst );
for ( int i = 0 ; i < nranks - 1 ; i ++ ) {
int tag = i ;
2024-03-26 06:08:55 -07:00
size_t rslice = ( rank - i - 1 + nranks ) % nranks ;
size_t sslice = ( rank - i + nranks ) % nranks ;
2024-09-10 05:57:10 -07:00
void * recv_data = data + rslice * size ;
void * send_data = data + sslice * size ;
NCCLCHECKGOTO ( netSendRecv ( net , sendComm , send_data , size , sendDataHandle , recvComm , recv_data , size , recvDataHandle , tag , abortFlag ), res , exit );
if ( i == 0 ) {
BOOTSTRAP_PROF_CLOSE ( tFirst );
BOOTSTRAP_PROF_OPEN ( tRest );
}
2024-03-26 06:08:55 -07:00
}
2024-09-10 05:57:10 -07:00
BOOTSTRAP_PROF_CLOSE ( tRest );
TRACE ( NCCL_BOOTSTRAP | NCCL_PROFILE , "netRingAllGather first message in %f (%f MB/sec), rest in %f (%f MB/sec)" , tFirst / 1e9 , ( size / 1e6 ) / ( tFirst / 1e9 ), tRest / 1e9 , ( nranks - 1 ) * ( size / 1e6 ) / ( tRest / 1e9 ));
exit :
// do not fail in case of error, try to deregister as much as possible
if ( sendDataHandle ) netDereg ( net , sendComm , & sendDataHandle );
if ( recvDataHandle ) netDereg ( net , recvComm , & recvDataHandle );
return res ;
}
static ncclResult_t socketRingAllGather ( struct ncclSocket * sendSock , struct ncclSocket * recvSock , int rank , int nranks , char * data , int size ) {
ncclResult_t res = ncclSuccess ;
uint64_t tFirst = 0 , tRest = 0 ;
/* Simple ring based AllGather
* At each step i receive data from (rank-i-1) from prev
* and send previous step's data from (rank-i) to next
*/
TRACE ( NCCL_BOOTSTRAP , "socketRingAllGather started" );
BOOTSTRAP_PROF_OPEN ( tFirst );
for ( int i = 0 ; i < nranks - 1 ; i ++ ) {
size_t rslice = ( rank - i - 1 + nranks ) % nranks ;
size_t sslice = ( rank - i + nranks ) % nranks ;
void * recv_data = data + rslice * size ;
void * send_data = data + sslice * size ;
NCCLCHECKGOTO ( socketSendRecv ( sendSock , send_data , size , recvSock , recv_data , size ), res , exit );
if ( i == 0 ) {
BOOTSTRAP_PROF_CLOSE ( tFirst );
BOOTSTRAP_PROF_OPEN ( tRest );
}
}
BOOTSTRAP_PROF_CLOSE ( tRest );
TRACE ( NCCL_BOOTSTRAP | NCCL_PROFILE , "socketRingAllGather first message in %f (%f MB/sec), rest in %f (%f MB/sec)" , tFirst / 1e9 , ( size / 1e6 ) / ( tFirst / 1e9 ), tRest / 1e9 , ( nranks - 1 ) * ( size / 1e6 ) / ( tRest / 1e9 ));
exit :
return res ;
2024-03-26 06:08:55 -07:00
}
ncclResult_t bootstrapAllGather ( void * commState , void * allData , int size ) {
2024-09-10 05:57:10 -07:00
ncclResult_t res = ncclSuccess ;
2024-03-26 06:08:55 -07:00
struct bootstrapState * state = ( struct bootstrapState * ) commState ;
int rank = state -> rank ;
int nranks = state -> nranks ;
2024-09-10 05:57:10 -07:00
TRACE ( NCCL_BOOTSTRAP , "rank %d nranks %d size %d - AllGather" , rank , nranks , size );
2024-03-26 06:08:55 -07:00
2024-09-10 05:57:10 -07:00
uint64_t time = 0 ;
BOOTSTRAP_PROF_OPEN ( time );
if ( ncclParamBootstrapNetEnable ()) {
NCCLCHECKGOTO ( netRingAllGather ( state -> net , STATE_RING ( state , net . sendComm ), STATE_RING ( state , net . recvComm ), rank , nranks , ( char * ) allData , size , state -> abortFlag ), res , exit );
} else {
NCCLCHECKGOTO ( socketRingAllGather ( & STATE_RING ( state , socket . send ), & STATE_RING ( state , socket . recv ), rank , nranks , ( char * ) allData , size ), res , exit );
}
exit :
BOOTSTRAP_PROF_CLOSE ( time );
TRACE ( NCCL_BOOTSTRAP | NCCL_PROFILE , "bootstrapAllGather for %d B done in %f sec: %f MB/sec" , size , time / 1e9 , ( nranks * size / 1e6 ) / ( time / 1e9 ));
TRACE ( NCCL_BOOTSTRAP , "rank %d nranks %d size %d - AllGather DONE" , rank , nranks , size );
return res ;
2024-03-26 06:08:55 -07:00
}
2024-09-10 05:57:10 -07:00
static ncclResult_t bootstrapP2PBarrier ( void * commState , int * ranks , int rank , int nranks , int tag ) {
if ( nranks == 1 )
return ncclSuccess ;
2024-03-26 06:08:55 -07:00
/* Simple [intra] process barrier
*
* Based on the dissemination algorithm by Debra Hensgen, Raphael Finkel, and Udi Manbet,
* "Two Algorithms for Barrier Synchronization," International Journal of Parallel Programming, 17(1):1-17, 1988"
*/
int data [ 1 ];
2024-09-10 05:57:10 -07:00
for ( int mask = 1 ; mask < nranks ; mask <<= 1 ) {
2024-03-26 06:08:55 -07:00
int src = ( rank - mask + nranks ) % nranks ;
int dst = ( rank + mask ) % nranks ;
NCCLCHECK ( bootstrapSend ( commState , ranks ? ranks [ dst ] : dst , tag , data , sizeof ( data )));
NCCLCHECK ( bootstrapRecv ( commState , ranks ? ranks [ src ] : src , tag , data , sizeof ( data )));
}
2024-09-10 05:57:10 -07:00
return ncclSuccess ;
}
2024-03-26 06:08:55 -07:00
2024-09-10 05:57:10 -07:00
ncclResult_t bootstrapIntraNodeBarrier ( void * commState , int * ranks , int rank , int nranks , int tag ) {
uint64_t time = 0 ;
BOOTSTRAP_PROF_OPEN ( time );
NCCLCHECK ( bootstrapP2PBarrier ( commState , ranks , rank , nranks , tag ));
BOOTSTRAP_PROF_CLOSE ( time );
TRACE ( NCCL_BOOTSTRAP | NCCL_PROFILE , "bootstrapIntraNodeBarrier done in %f sec" , time / 1e9 );
2024-03-26 06:08:55 -07:00
return ncclSuccess ;
}
ncclResult_t bootstrapBarrier ( void * commState , int rank , int nranks , int tag ) {
2024-09-10 05:57:10 -07:00
uint64_t time = 0 ;
BOOTSTRAP_PROF_OPEN ( time );
NCCLCHECK ( bootstrapP2PBarrier ( commState , NULL , rank , nranks , tag ));
BOOTSTRAP_PROF_CLOSE ( time );
TRACE ( NCCL_BOOTSTRAP | NCCL_PROFILE , "bootstrapBarrier done in %f sec" , time / 1e9 );
return ncclSuccess ;
2024-03-26 06:08:55 -07:00
}
2024-09-10 05:57:10 -07:00
ncclResult_t bootstrapIntraNodeAllGather ( void * commState , int * ranks , int rank , int nranks , void * allData , int size ) {
2024-03-26 06:08:55 -07:00
if ( nranks == 1 ) return ncclSuccess ;
TRACE ( NCCL_INIT , "rank %d nranks %d size %d - ENTER" , rank , nranks , size );
2024-09-10 05:57:10 -07:00
int prevRank = ranks [( rank - 1 + nranks ) % nranks ];
2024-03-26 06:08:55 -07:00
int nextRank = ranks [( rank + 1 ) % nranks ];
2024-09-10 05:57:10 -07:00
// intraNode bootstrap is done defacto using the socket-based implementation
struct ncclSocket recvSocket , sendSocket ;
NCCLCHECK ( socketConnect ( commState , nextRank , BOOTSTRAP_TAG_INTRANODE_ALLGATHER , & sendSocket ));
NCCLCHECK ( socketAccept ( commState , prevRank , BOOTSTRAP_TAG_INTRANODE_ALLGATHER , & recvSocket ));
2024-03-26 06:08:55 -07:00
2024-09-10 05:57:10 -07:00
NCCLCHECK ( socketRingAllGather ( & sendSocket , & recvSocket , rank , nranks , ( char * ) allData , size ));
2024-03-26 06:08:55 -07:00
2024-09-10 05:57:10 -07:00
NCCLCHECK ( ncclSocketClose ( & sendSocket ));
NCCLCHECK ( ncclSocketClose ( & recvSocket ));
2024-03-26 06:08:55 -07:00
TRACE ( NCCL_INIT , "rank %d nranks %d size %d - DONE" , rank , nranks , size );
return ncclSuccess ;
}
// [IntraNode] in-place Broadcast
2024-09-10 05:57:10 -07:00
static ncclResult_t bootstrapP2PBroadcast ( void * commState , int * ranks , int rank , int nranks , int root , void * bcastData , int size ) {
2024-03-26 06:08:55 -07:00
if ( nranks == 1 ) return ncclSuccess ;
if ( rank == root ) {
2024-09-10 05:57:10 -07:00
for ( int i = 0 ; i < nranks ; i ++ ) {
2024-03-26 06:08:55 -07:00
if ( i != root ) NCCLCHECK ( bootstrapSend ( commState , ranks ? ranks [ i ] : i , /*tag=*/ ranks ? ranks [ i ] : i , bcastData , size ));
}
2024-09-10 05:57:10 -07:00
} else {
2024-03-26 06:08:55 -07:00
NCCLCHECK ( bootstrapRecv ( commState , ranks ? ranks [ root ] : root , /*tag=*/ ranks ? ranks [ rank ] : rank , bcastData , size ));
}
return ncclSuccess ;
}
2024-09-10 05:57:10 -07:00
ncclResult_t bootstrapIntraNodeBroadcast ( void * commState , int * ranks , int rank , int nranks , int root , void * bcastData , int size ) {
uint64_t time = 0 ;
BOOTSTRAP_PROF_OPEN ( time );
NCCLCHECK ( bootstrapP2PBroadcast ( commState , ranks , rank , nranks , root , bcastData , size ));
BOOTSTRAP_PROF_CLOSE ( time );
TRACE ( NCCL_BOOTSTRAP | NCCL_PROFILE , "bootstrapIntraNodeBroadcast for %d B done in %f sec: %f MB/sec" , size , time / 1e9 , ( nranks * size / 1e6 ) / ( time / 1e9 ));
return ncclSuccess ;
}
2024-03-26 06:08:55 -07:00
ncclResult_t bootstrapBroadcast ( void * commState , int rank , int nranks , int root , void * bcastData , int size ) {
2024-09-10 05:57:10 -07:00
uint64_t time = 0 ;
BOOTSTRAP_PROF_OPEN ( time );
NCCLCHECK ( bootstrapP2PBroadcast ( commState , NULL , rank , nranks , root , bcastData , size ));
BOOTSTRAP_PROF_CLOSE ( time );
TRACE ( NCCL_BOOTSTRAP | NCCL_PROFILE , "bootstrapBroadcast done in %f sec" , time / 1e9 );
return ncclSuccess ;
2018-12-13 15:56:12 -08:00
}
ncclResult_t bootstrapClose ( void * commState ) {
2024-09-10 05:57:10 -07:00
if ( commState == NULL )
return ncclSuccess ;
2022-01-07 06:39:55 -08:00
struct bootstrapState * state = ( struct bootstrapState * ) commState ;
2024-09-10 05:57:10 -07:00
// close unexpected and return an error if we are not aborting and still operations in the pipe
2018-12-13 15:56:12 -08:00
if ( state -> unexpectedConnections != NULL ) {
2022-11-29 04:27:46 -08:00
unexpectedFree ( state );
2024-06-11 01:28:01 -07:00
if ( __atomic_load_n ( state -> abortFlag , __ATOMIC_ACQUIRE ) == 0 ) {
2022-11-29 04:27:46 -08:00
WARN ( "Unexpected connections are not empty" );
return ncclInternalError ;
}
2018-12-13 15:56:12 -08:00
}
2024-09-10 05:57:10 -07:00
if ( ncclParamBootstrapNetEnable ()) {
NCCLCHECK ( state -> net -> closeSend ( STATE_RING ( state , net . sendComm )));
NCCLCHECK ( state -> net -> closeRecv ( STATE_RING ( state , net . recvComm )));
NCCLCHECK ( state -> net -> closeListen ( STATE_LISTEN ( state , net . comm )));
} else {
NCCLCHECK ( ncclSocketClose ( & STATE_RING ( state , socket . send )));
NCCLCHECK ( ncclSocketClose ( & STATE_RING ( state , socket . recv )));
NCCLCHECK ( ncclSocketClose ( & STATE_LISTEN ( state , socket )));
}
// close the p2p socket
NCCLCHECK ( ncclSocketClose ( & STATE_LISTEN ( state , peerSocket )));
2022-11-29 04:27:46 -08:00
2024-09-10 05:57:10 -07:00
// proxy things are free'd elsewhere
free ( state -> peerP2pAddresses );
2018-09-24 16:06:59 -07:00
free ( state );
return ncclSuccess ;
}
2019-11-19 14:57:39 -08:00
ncclResult_t bootstrapAbort ( void * commState ) {
2024-09-10 05:57:10 -07:00
if ( commState == NULL )
return ncclSuccess ;
2022-01-07 06:39:55 -08:00
struct bootstrapState * state = ( struct bootstrapState * ) commState ;
2024-09-10 05:57:10 -07:00
// when aborting we need to close the proxy here (maybe?)
2022-01-07 06:39:55 -08:00
free ( state -> peerProxyAddresses );
2024-02-05 05:06:02 -08:00
free ( state -> peerProxyAddressesUDS );
2024-09-10 05:57:10 -07:00
NCCLCHECK ( bootstrapClose ( commState ));
2019-11-19 14:57:39 -08:00
return ncclSuccess ;
}