@@ -318,6 +318,7 @@ flagcxProxyGetPostedOps(struct flagcxProxyState *proxyState, int *added) {
318318}
319319
320320FLAGCX_PARAM (ProgressAppendOpFreq, " PROGRESS_APPENDOP_FREQ" , 8 );
321+ FLAGCX_PARAM (KernelProxyParallelism, " KERNEL_PROXY_PARALLELISM" , 4 );
321322
322323inline void *flagcxProxyProgress (void *proxyState_) {
323324 struct flagcxProxyState *proxyState = (flagcxProxyState *)proxyState_;
@@ -856,6 +857,11 @@ flagcxResult_t flagcxProxyCallBlocking(struct flagcxHeteroComm *comm,
856857 goto exit;
857858}
858859
860+ struct flagcxProxyKernelServiceArg {
861+ struct flagcxHeteroComm *comm;
862+ int contextId;
863+ };
864+
859865flagcxResult_t flagcxProxyInit (struct flagcxHeteroComm *comm) {
860866 INFO (FLAGCX_INIT , " rank=%d flagcxProxyInit called." , comm->rank );
861867 FLAGCXCHECK (flagcxSocketInit (&comm->proxyState ->listenSock ,
@@ -877,21 +883,45 @@ flagcxResult_t flagcxProxyInit(struct flagcxHeteroComm *comm) {
877883 pthread_create (&comm->proxyState ->progressState .thread , NULL ,
878884 flagcxProxyProgress, comm->proxyState );
879885#ifdef COMPILE_KERNEL_HOST
880- // Initialize synchronization primitives before creating thread
886+ // Initialize synchronization primitives before creating threads
881887 pthread_mutex_init (&comm->proxyState ->kernelState .initMutex , NULL );
882888 pthread_cond_init (&comm->proxyState ->kernelState .initCond , NULL );
883889 comm->proxyState ->kernelState .ready = 0 ;
884890
885- pthread_create (&comm->proxyState ->kernelState .thread , NULL ,
886- flagcxProxyKernelService, (void *)comm);
891+ int nKernelProxies = flagcxParamKernelProxyParallelism ();
892+ if (nKernelProxies < 1 )
893+ nKernelProxies = 1 ;
894+ if (nKernelProxies > FLAGCX_DEVICE_CTA_COUNT )
895+ nKernelProxies = FLAGCX_DEVICE_CTA_COUNT ;
896+ comm->proxyState ->kernelState .contextCount = nKernelProxies;
897+
898+ int nStarted = 0 ;
899+ for (int i = 0 ; i < nKernelProxies; i++) {
900+ flagcxProxyKernelServiceArg *arg = new flagcxProxyKernelServiceArg{comm, i};
901+ if (pthread_create (&comm->proxyState ->kernelState .threads [i], NULL ,
902+ flagcxProxyKernelService, arg) != 0 ) {
903+ WARN (" flagcxProxyInit: failed to create kernel proxy thread %d" , i);
904+ delete arg;
905+ break ;
906+ }
907+ nStarted++;
908+ }
909+ // Adjust contextCount to the number of threads actually started so the
910+ // cond-wait below and the stop/join loop use a consistent count.
911+ comm->proxyState ->kernelState .contextCount = nStarted;
887912
888- // Wait for kernel proxy thread to finish initialization
913+ // Wait for all started kernel proxy threads to finish initialization
889914 pthread_mutex_lock (&comm->proxyState ->kernelState .initMutex );
890- while (comm->proxyState ->kernelState .ready == 0 ) {
915+ while (comm->proxyState ->kernelState .ready < nStarted ) {
891916 pthread_cond_wait (&comm->proxyState ->kernelState .initCond ,
892917 &comm->proxyState ->kernelState .initMutex );
893918 }
894919 pthread_mutex_unlock (&comm->proxyState ->kernelState .initMutex );
920+
921+ if (nStarted == 0 ) {
922+ WARN (" flagcxProxyInit: no kernel proxy threads started" );
923+ return flagcxSystemError;
924+ }
895925#endif
896926
897927 comm->proxyState ->initialized = 1 ;
@@ -1003,8 +1033,10 @@ void *flagcxProxyService(void *args) {
10031033 pthread_mutex_unlock (&comm->proxyState ->mutex );
10041034 pthread_join (comm->proxyState ->progressState .thread , nullptr );
10051035#ifdef COMPILE_KERNEL_HOST
1006- // Stop kernel thread and cleanup its mutex/cond
1007- pthread_join (comm->proxyState ->kernelState .thread , nullptr );
1036+ // Stop all kernel threads and cleanup
1037+ for (int i = 0 ; i < comm->proxyState ->kernelState .contextCount ; i++) {
1038+ pthread_join (comm->proxyState ->kernelState .threads [i], nullptr );
1039+ }
10081040 pthread_mutex_destroy (&comm->proxyState ->kernelState .initMutex );
10091041 pthread_cond_destroy (&comm->proxyState ->kernelState .initCond );
10101042#endif
@@ -1056,7 +1088,11 @@ void *flagcxProxyKernelService(void *args) {
10561088 int termCount = 0 ;
10571089 flagcxDeviceTrigger_t ptr = NULL ;
10581090 flagcxFifo_t fifo = NULL ;
1059- struct flagcxHeteroComm *comm = (struct flagcxHeteroComm *)args;
1091+ flagcxStream_t stream = NULL ;
1092+ flagcxProxyKernelServiceArg *arg = (flagcxProxyKernelServiceArg *)args;
1093+ struct flagcxHeteroComm *comm = arg->comm ;
1094+ int contextId = arg->contextId ;
1095+ delete arg;
10601096 flagcxResult_t res = flagcxSuccess;
10611097
10621098 auto validateOneSidedPeer = [](struct flagcxHeteroComm *comm,
@@ -1079,19 +1115,19 @@ void *flagcxProxyKernelService(void *args) {
10791115 // Set device context
10801116 FLAGCXCHECKGOTO (deviceAdaptor->setDevice (comm->cudaDev ), res, out);
10811117
1082- // Create FIFO
1083- comm->proxyState ->kernelState .fifo = new flagcxFifo ();
1084- FLAGCXCHECKGOTO (comm->proxyState ->kernelState .fifo ->flagcxFifoInit (), res,
1085- out);
1086- fifo = comm->proxyState ->kernelState .fifo ;
1087- // comm->fifoBuffer = (void *)comm->proxyState->kernelState.fifo->buffer;
1088- FLAGCXCHECKGOTO (deviceAdaptor->hostGetDevicePointer (
1089- &comm->fifoBuffer ,
1090- (void *)comm->proxyState ->kernelState .fifo ->buffer ),
1091- res, out);
1118+ // Create FIFO for this thread
1119+ comm->proxyState ->kernelState .fifos [contextId] = new flagcxFifo ();
1120+ FLAGCXCHECKGOTO (
1121+ comm->proxyState ->kernelState .fifos [contextId]->flagcxFifoInit (), res,
1122+ out);
1123+ fifo = comm->proxyState ->kernelState .fifos [contextId];
1124+ FLAGCXCHECKGOTO (
1125+ deviceAdaptor->hostGetDevicePointer (
1126+ &comm->fifoBuffers [contextId],
1127+ (void *)comm->proxyState ->kernelState .fifos [contextId]->buffer ),
1128+ res, out);
10921129
10931130 // Create a dedicated stream
1094- flagcxStream_t stream;
10951131 FLAGCXCHECKGOTO (deviceAdaptor->streamCreate (&stream), res, out);
10961132 INFO (FLAGCX_P2P , " rank %d p2p stream %lu" , comm->rank , (uintptr_t )stream);
10971133
@@ -1100,8 +1136,8 @@ void *flagcxProxyKernelService(void *args) {
11001136
11011137 // Signal that initialization is complete
11021138 pthread_mutex_lock (&comm->proxyState ->kernelState .initMutex );
1103- comm->proxyState ->kernelState .ready = 1 ;
1104- pthread_cond_signal (&comm->proxyState ->kernelState .initCond );
1139+ comm->proxyState ->kernelState .ready ++ ;
1140+ pthread_cond_broadcast (&comm->proxyState ->kernelState .initCond );
11051141 pthread_mutex_unlock (&comm->proxyState ->kernelState .initMutex );
11061142
11071143 while (true ) {
@@ -1341,17 +1377,21 @@ void *flagcxProxyKernelService(void *args) {
13411377 if (res != flagcxSuccess)
13421378 break ;
13431379 }
1344- // destroy stream
1345- res = deviceAdaptor->streamSynchronize (stream);
1346- res = deviceAdaptor->streamDestroy (stream);
1347- // deallocate trigger structure
1348- free (ptr);
1349-
13501380out:
1351- // destroy fifo
1352- res = comm->proxyState ->kernelState .fifo ->flagcxFifoDestroy ();
1353- delete comm->proxyState ->kernelState .fifo ;
1354- comm->fifoBuffer = NULL ;
1381+ // destroy stream (only if created)
1382+ if (stream != nullptr ) {
1383+ deviceAdaptor->streamSynchronize (stream);
1384+ deviceAdaptor->streamDestroy (stream);
1385+ }
1386+ // deallocate trigger structure (only if allocated)
1387+ free (ptr);
1388+ // destroy fifo (only if created)
1389+ if (comm->proxyState ->kernelState .fifos [contextId] != nullptr ) {
1390+ comm->proxyState ->kernelState .fifos [contextId]->flagcxFifoDestroy ();
1391+ delete comm->proxyState ->kernelState .fifos [contextId];
1392+ comm->proxyState ->kernelState .fifos [contextId] = nullptr ;
1393+ }
1394+ comm->fifoBuffers [contextId] = NULL ;
13551395 return NULL ;
13561396}
13571397
0 commit comments