Skip to content

Commit 6e9f3e4

Browse files
authored
Add bootstrap alltoallv (#172)
1 parent 19bc8ed commit 6e9f3e4

4 files changed

Lines changed: 107 additions & 4 deletions

File tree

flagcx/adaptor/bootstrap_adaptor.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,13 +151,14 @@ flagcxResult_t bootstrapAdaptorAlltoAll(const void *sendbuff, void *recvbuff,
151151
return flagcxSuccess;
152152
}
153153

154-
// TODO: unsupported
155154
flagcxResult_t
156155
bootstrapAdaptorAlltoAllv(const void *sendbuff, size_t *sendcounts,
157156
size_t *sdispls, void *recvbuff, size_t *recvcounts,
158157
size_t *rdispls, flagcxDataType_t datatype,
159158
flagcxInnerComm_t comm, flagcxStream_t /*stream*/) {
160-
return flagcxNotSupported;
159+
FLAGCXCHECK(AlltoAllvBootstrap(comm->base, sendbuff, sendcounts, sdispls,
160+
recvbuff, recvcounts, rdispls, datatype));
161+
return flagcxSuccess;
161162
}
162163

163164
#define BOOTSTRAP_SEND_RECV_TAG -6767

flagcx/flagcx.cc

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1363,8 +1363,53 @@ flagcxResult_t flagcxAlltoAllv(const void *sendbuff, size_t *sendcounts,
13631363
comm->homo_comm, stream);
13641364
} else {
13651365
if (use_host_comm()) {
1366-
// TODO: to be implemented
1367-
return flagcxNotSupported;
1366+
uint64_t timers[TIMERS_COLL_COUNT] = {0};
1367+
timers[TIMER_COLL_TOTAL] = clockNano();
1368+
void *buff_in;
1369+
void *buff_out;
1370+
1371+
// Calculate max possible size needed for send and receive buffers
1372+
size_t max_send_size = 0, max_recv_size = 0 , send_size = 0 , recv_size = 0;
1373+
for (int i = 0; i < comm->nranks; i++) {
1374+
send_size = (sendcounts[i] + sdispls[i]) * getFlagcxDataTypeSize(datatype);
1375+
recv_size = (recvcounts[i] + rdispls[i]) * getFlagcxDataTypeSize(datatype);
1376+
if (send_size > max_send_size) max_send_size = send_size;
1377+
if (recv_size > max_recv_size) max_recv_size = recv_size;
1378+
}
1379+
timers[TIMER_COLL_ALLOC] = clockNano();
1380+
deviceAdaptor->deviceMalloc(&buff_in, max_send_size, flagcxMemHost, NULL);
1381+
deviceAdaptor->deviceMalloc(&buff_out, max_recv_size, flagcxMemHost, NULL);
1382+
timers[TIMER_COLL_ALLOC] = clockNano() - timers[TIMER_COLL_ALLOC];
1383+
1384+
timers[TIMER_COLL_MEM_D2H] = clockNano();
1385+
deviceAdaptor->deviceMemcpy(buff_in, const_cast<void *>(sendbuff), max_send_size,
1386+
flagcxMemcpyDeviceToHost, NULL, NULL);
1387+
timers[TIMER_COLL_MEM_D2H] = clockNano() - timers[TIMER_COLL_MEM_D2H];
1388+
1389+
timers[TIMER_COLL_COMM] = clockNano();
1390+
cclAdaptors[flagcxCCLAdaptorHost]->alltoAllv(
1391+
buff_in, sendcounts, sdispls, buff_out, recvcounts, rdispls, datatype,
1392+
comm->host_comm, NULL);
1393+
timers[TIMER_COLL_COMM] = clockNano() - timers[TIMER_COLL_COMM];
1394+
1395+
timers[TIMER_COLL_MEM_H2D] = clockNano();
1396+
deviceAdaptor->deviceMemcpy(recvbuff, buff_out, max_recv_size,
1397+
flagcxMemcpyHostToDevice, NULL, NULL);
1398+
timers[TIMER_COLL_MEM_H2D] = clockNano() - timers[TIMER_COLL_MEM_H2D];
1399+
1400+
timers[TIMER_COLL_FREE] = clockNano();
1401+
deviceAdaptor->deviceFree(buff_in, flagcxMemHost, NULL);
1402+
deviceAdaptor->deviceFree(buff_out, flagcxMemHost, NULL);
1403+
timers[TIMER_COLL_FREE] = clockNano() - timers[TIMER_COLL_FREE];
1404+
1405+
timers[TIMER_COLL_TOTAL] = clockNano() - timers[TIMER_COLL_TOTAL];
1406+
INFO(FLAGCX_COLL,
1407+
"Flagcx timings - %s AlltoAllv: rank %d nranks %d total %.2fms "
1408+
"(memory alloc %.2fms, memory free %.2fms, memory d2h %.2fms, memory h2d %.2fms, comm %.2fms)",
1409+
cclAdaptors[flagcxCCLAdaptorHost]->name, comm->rank, comm->nranks,
1410+
timers[TIMER_COLL_TOTAL] / 1e6, timers[TIMER_COLL_ALLOC] / 1e6,
1411+
timers[TIMER_COLL_FREE] / 1e6, timers[TIMER_COLL_MEM_D2H] / 1e6,
1412+
timers[TIMER_COLL_MEM_H2D] / 1e6, timers[TIMER_COLL_COMM] / 1e6);
13681413
} else {
13691414
// Move it into flagcxC2cPlanner workflow
13701415
flagcxC2cPlanner planner;

flagcx/service/bootstrap.cc

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -997,3 +997,41 @@ flagcxResult_t bootstrapAbort(void* commState) {
997997
free(state);
998998
return flagcxSuccess;
999999
}
1000+
// AlltoALlv require sendbuff and recvbuff not overlap
1001+
flagcxResult_t AlltoAllvBootstrap(void* commState, const void* sendbuff, size_t* sendcounts, size_t* sdispls,
1002+
void* recvbuff, size_t* recvcounts, size_t* rdispls, flagcxDataType_t datatype){
1003+
struct bootstrapState* state = (struct bootstrapState*)commState;
1004+
int rank = state->rank;
1005+
int nranks = state->nranks;
1006+
size_t typeSize = getFlagcxDataTypeSize(datatype);
1007+
1008+
for (int i = 0; i < nranks; ++i) {
1009+
if (i == rank) {
1010+
memcpy((void *)((char*)recvbuff + rdispls[i] * typeSize),
1011+
(void *)((char *)sendbuff + sdispls[i] * typeSize),
1012+
sendcounts[i] * typeSize);
1013+
}
1014+
const int bootstrapTag = -9995; // Suggest making this unique if possible
1015+
if (rank > i) {
1016+
// Send to rank i
1017+
FLAGCXCHECK(bootstrapSend(commState, i, bootstrapTag,
1018+
(void *)((char *)sendbuff + sdispls[i] * typeSize),
1019+
sendcounts[i] * typeSize));
1020+
// Recv from rank i
1021+
FLAGCXCHECK(bootstrapRecv(commState, i, bootstrapTag,
1022+
(void *)((char *)recvbuff + rdispls[i] * typeSize),
1023+
recvcounts[i] * typeSize));
1024+
} else if (rank < i) {
1025+
// Receive from rank i
1026+
FLAGCXCHECK(bootstrapRecv(commState, i, bootstrapTag,
1027+
(void *)((char *)recvbuff + rdispls[i] * typeSize),
1028+
recvcounts[i] * typeSize));
1029+
// Send to rank i
1030+
FLAGCXCHECK(bootstrapSend(commState, i, bootstrapTag,
1031+
(void *)((char *)sendbuff + sdispls[i] * typeSize),
1032+
sendcounts[i] * typeSize));
1033+
}
1034+
}
1035+
return flagcxSuccess;
1036+
}
1037+

flagcx/service/bootstrap.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,25 @@ flagcxResult_t ReduceScatterBootstrap(void* commState, const void* sendbuff, voi
151151
*/
152152
flagcxResult_t AlltoAllBootstrap(void* commState, const void* sendbuff, void* recvbuff, size_t count,
153153
flagcxDataType_t datatype);
154+
155+
/*
156+
* All-to-all with variable block sizes
157+
*
158+
* Every rank sends j-th block of its own sendbuff to the j-th rank of the communicator.
159+
* Meanwhile, every rank receives j-th block of its own recvbuff from j-th rank.
160+
*
161+
* Each block can have different sizes:
162+
* - sendcounts[j] specifies the number of elements to send to rank j
163+
* - sdispls[j] specifies the offset in sendbuff for the j-th block
164+
* - recvcounts[j] specifies the number of elements to receive from rank j
165+
* - rdispls[j] specifies the offset in recvbuff for the j-th block
166+
*
167+
* In-place operations will happen if sendbuff == recvbuff.
168+
*/
169+
flagcxResult_t AlltoAllvBootstrap(void* commState, const void* sendbuff, size_t* sendcounts, size_t* sdispls,
170+
void* recvbuff, size_t* recvcounts, size_t* rdispls,
171+
flagcxDataType_t datatype);
172+
154173
#ifdef __cplusplus
155174
} // end extern "C"
156175
#endif

0 commit comments

Comments
 (0)