int ompi_coll_libnbc_ineighbor_allgatherv(void *sbuf, int scount, MPI_Datatype stype, void *rbuf, int *rcounts, int *displs, MPI_Datatype rtype, struct ompi_communicator_t *comm, ompi_request_t ** request, struct mca_coll_base_module_2_1_0_t *module) { int rank, size, res, worldsize; MPI_Aint sndext, rcvext; NBC_Handle *handle; ompi_coll_libnbc_request_t **coll_req = (ompi_coll_libnbc_request_t**) request; ompi_coll_libnbc_module_t *libnbc_module = (ompi_coll_libnbc_module_t*) module; res = NBC_Init_handle(comm, coll_req, libnbc_module); handle = *coll_req; if(res != NBC_OK) { printf("Error in NBC_Init_handle(%i)\n", res); return res; } res = MPI_Comm_size(comm, &size); if (MPI_SUCCESS != res) { printf("MPI Error in MPI_Comm_size() (%i)\n", res); return res; } res = MPI_Comm_size(MPI_COMM_WORLD, &worldsize); if (MPI_SUCCESS != res) { printf("MPI Error in MPI_Comm_size() (%i)\n", res); return res; } res = MPI_Comm_rank(comm, &rank); if (MPI_SUCCESS != res) { printf("MPI Error in MPI_Comm_rank() (%i)\n", res); return res; } res = MPI_Type_extent(stype, &sndext); if (MPI_SUCCESS != res) { printf("MPI Error in MPI_Type_extent() (%i)\n", res); return res; } res = MPI_Type_extent(rtype, &rcvext); if (MPI_SUCCESS != res) { printf("MPI Error in MPI_Type_extent() (%i)\n", res); return res; } char inplace; NBC_Schedule *schedule; #ifdef NBC_CACHE_SCHEDULE NBC_Ineighbor_allgatherv_args *args, *found, search; #endif NBC_IN_PLACE(sbuf, rbuf, inplace); handle->tmpbuf=NULL; #ifdef NBC_CACHE_SCHEDULE /* search schedule in communicator specific tree */ search.sbuf=sbuf; search.scount=scount; search.stype=stype; search.rbuf=rbuf; search.rcount=rcount; search.rtype=rtype; found = (NBC_Ineighbor_allgatherv_args*)hb_tree_search((hb_tree*)handle->comminfo->NBC_Dict[NBC_NEIGHBOR_ALLGATHERV], &search); if(found == NULL) { #endif schedule = (NBC_Schedule*)malloc(sizeof(NBC_Schedule)); res = NBC_Sched_create(schedule); if(res != NBC_OK) { printf("Error in NBC_Sched_create, res = %i\n", res); return res; } { int indegree, outdegree, weighted, *srcs, *dsts, i; res = NBC_Comm_neighbors_count(comm, &indegree, &outdegree, &weighted); if(res != NBC_OK) return res; srcs = (int*)malloc(sizeof(int)*indegree); dsts = (int*)malloc(sizeof(int)*outdegree); res = NBC_Comm_neighbors(comm, indegree, srcs, MPI_UNWEIGHTED, outdegree, dsts, MPI_UNWEIGHTED); if(res != NBC_OK) return res; if(inplace) { /* we need an extra buffer to be deadlock-free */ int sumrcounts=0; int offset=0; for(i=0; i<indegree; ++i) sumrcounts += rcounts[i]; handle->tmpbuf = malloc(rcvext*sumrcounts); for(i = 0; i < indegree; i++) { if(srcs[i] != MPI_PROC_NULL) { res = NBC_Sched_recv((char*)0+offset, true, rcounts[i], rtype, srcs[i], schedule); if (NBC_OK != res) { printf("Error in NBC_Sched_recv() (%i)\n", res); return res; } } offset += rcounts[i]*rcvext; } for(i = 0; i < outdegree; i++) { if(dsts[i] != MPI_PROC_NULL) { res = NBC_Sched_send((char*)sbuf, false, scount, stype, dsts[i], schedule); if (NBC_OK != res) { printf("Error in NBC_Sched_send() (%i)\n", res); return res; } } } /* unpack from buffer */ offset=0; for(i = 0; i < indegree; i++) { if(srcs[i] != MPI_PROC_NULL) { res = NBC_Sched_barrier(schedule); if (NBC_OK != res) { printf("Error in NBC_Sched_barrier() (%i)\n", res); return res; } res = NBC_Sched_copy((char*)0+offset, true, rcounts[i], rtype, (char*)rbuf+displs[i]*rcvext, false, rcounts[i], rtype, schedule); if (NBC_OK != res) { printf("Error in NBC_Sched_copy() (%i)\n", res); return res; } } offset += rcounts[i]*rcvext; } } else { /* non INPLACE case */ /* simply loop over neighbors and post send/recv operations */ for(i = 0; i < indegree; i++) { if(srcs[i] != MPI_PROC_NULL) { res = NBC_Sched_recv((char*)rbuf+displs[i]*rcvext, false, rcounts[i], rtype, srcs[i], schedule); if (NBC_OK != res) { printf("Error in NBC_Sched_recv() (%i)\n", res); return res; } } } for(i = 0; i < outdegree; i++) { if(dsts[i] != MPI_PROC_NULL) { res = NBC_Sched_send((char*)sbuf, false, scount, stype, dsts[i], schedule); if (NBC_OK != res) { printf("Error in NBC_Sched_send() (%i)\n", res); return res; } } } } } res = NBC_Sched_commit(schedule); if (NBC_OK != res) { printf("Error in NBC_Sched_commit() (%i)\n", res); return res; } #ifdef NBC_CACHE_SCHEDULE /* save schedule to tree */ args = (NBC_Ineighbor_allgatherv_args*)malloc(sizeof(NBC_Ineighbor_allgatherv_args)); args->sbuf=sbuf; args->scount=scount; args->stype=stype; args->rbuf=rbuf; args->rcount=rcount; args->rtype=rtype; args->schedule=schedule; res = hb_tree_insert ((hb_tree*)handle->comminfo->NBC_Dict[NBC_NEIGHBOR_ALLGATHERV], args, args, 0); if(res != 0) printf("error in dict_insert() (%i)\n", res); /* increase number of elements for A2A */ if(++handle->comminfo->NBC_Dict_size[NBC_NEIGHBOR_ALLGATHERV] > NBC_SCHED_DICT_UPPER) { NBC_SchedCache_dictwipe((hb_tree*)handle->comminfo->NBC_Dict[NBC_NEIGHBOR_ALLGATHERV], &handle->comminfo->NBC_Dict_size[NBC_NEIGHBOR_ALLGATHERV]); } } else { /* found schedule */ schedule=found->schedule; } #endif res = NBC_Start(handle, schedule); if (NBC_OK != res) { printf("Error in NBC_Start() (%i)\n", res); return res; } return NBC_OK; }
int ompi_coll_libnbc_ireduce_scatter(void* sendbuf, void* recvbuf, int *recvcounts, MPI_Datatype datatype, MPI_Op op, struct ompi_communicator_t *comm, ompi_request_t ** request, struct mca_coll_base_module_2_0_0_t *module) { int peer, rank, maxr, p, r, res, count, offset, firstred; MPI_Aint ext; char *redbuf, *sbuf, inplace; NBC_Schedule *schedule; NBC_Handle *handle; ompi_coll_libnbc_request_t **coll_req = (ompi_coll_libnbc_request_t**) request; ompi_coll_libnbc_module_t *libnbc_module = (ompi_coll_libnbc_module_t*) module; NBC_IN_PLACE(sendbuf, recvbuf, inplace); res = NBC_Init_handle(comm, coll_req, libnbc_module); if(res != NBC_OK) { printf("Error in NBC_Init_handle(%i)\n", res); return res; } handle = (*coll_req); res = MPI_Comm_rank(comm, &rank); if (MPI_SUCCESS != res) { printf("MPI Error in MPI_Comm_rank() (%i)\n", res); return res; } res = MPI_Comm_size(comm, &p); if (MPI_SUCCESS != res) { printf("MPI Error in MPI_Comm_size() (%i)\n", res); return res; } MPI_Type_extent(datatype, &ext); if (MPI_SUCCESS != res) { printf("MPI Error in MPI_Type_extent() (%i)\n", res); return res; } schedule = (NBC_Schedule*)malloc(sizeof(NBC_Schedule)); if (NULL == schedule) { printf("Error in malloc()\n"); return NBC_OOR; } res = NBC_Sched_create(schedule); if(res != NBC_OK) { printf("Error in NBC_Sched_create (%i)\n", res); return res; } maxr = (int)ceil((log(p)/LOG2)); count = 0; for(r=0;r<p;r++) count += recvcounts[r]; handle->tmpbuf = malloc(ext*count*2); if(handle->tmpbuf == NULL) { printf("Error in malloc()\n"); return NBC_OOR; } redbuf = ((char*)handle->tmpbuf)+(ext*count); /* copy data to redbuf if we only have a single node */ if((p==1) && !inplace) { res = NBC_Copy(sendbuf, count, datatype, redbuf, count, datatype, comm); if (NBC_OK != res) { printf("Error in NBC_Copy() (%i)\n", res); return res; } } firstred = 1; for(r=1; r<=maxr; r++) { if((rank % (1<<r)) == 0) { /* we have to receive this round */ peer = rank + (1<<(r-1)); if(peer<p) { res = NBC_Sched_recv(0, true, count, datatype, peer, schedule); if (NBC_OK != res) { free(handle->tmpbuf); printf("Error in NBC_Sched_recv() (%i)\n", res); return res; } /* we have to wait until we have the data */ res = NBC_Sched_barrier(schedule); if (NBC_OK != res) { free(handle->tmpbuf); printf("Error in NBC_Sched_barrier() (%i)\n", res); return res; } if(firstred) { /* take reduce data from the sendbuf in the first round -> save copy */ res = NBC_Sched_op(redbuf-(unsigned long)handle->tmpbuf, true, sendbuf, false, 0, true, count, datatype, op, schedule); firstred = 0; } else { /* perform the reduce in my local buffer */ res = NBC_Sched_op(redbuf-(unsigned long)handle->tmpbuf, true, redbuf-(unsigned long)handle->tmpbuf, true, 0, true, count, datatype, op, schedule); } if (NBC_OK != res) { free(handle->tmpbuf); printf("Error in NBC_Sched_op() (%i)\n", res); return res; } /* this cannot be done until handle->tmpbuf is unused :-( */ res = NBC_Sched_barrier(schedule); if (NBC_OK != res) { free(handle->tmpbuf); printf("Error in NBC_Sched_barrier() (%i)\n", res); return res; } } } else { /* we have to send this round */ peer = rank - (1<<(r-1)); if(firstred) { /* we have to send the senbuf */ res = NBC_Sched_send(sendbuf, false, count, datatype, peer, schedule); } else { /* we send an already reduced value from redbuf */ res = NBC_Sched_send(redbuf-(unsigned long)handle->tmpbuf, true, count, datatype, peer, schedule); } if (NBC_OK != res) { free(handle->tmpbuf); printf("Error in NBC_Sched_send() (%i)\n", res); return res; } /* leave the game */ break; } } res = NBC_Sched_barrier(schedule); if (NBC_OK != res) { free(handle->tmpbuf); printf("Error in NBC_Sched_barrier() (%i)\n", res); return res; } /* rank 0 is root and sends - all others receive */ if(rank != 0) { res = NBC_Sched_recv(recvbuf, false, recvcounts[rank], datatype, 0, schedule); if (NBC_OK != res) { free(handle->tmpbuf); printf("Error in NBC_Sched_recv() (%i)\n", res); return res; } } if(rank == 0) { offset = 0; for(r=1;r<p;r++) { offset += recvcounts[r-1]; sbuf = ((char *)redbuf) + (offset*ext); /* root sends the right buffer to the right receiver */ res = NBC_Sched_send(sbuf-(unsigned long)handle->tmpbuf, true, recvcounts[r], datatype, r, schedule); if (NBC_OK != res) { free(handle->tmpbuf); printf("Error in NBC_Sched_send() (%i)\n", res); return res; } } res = NBC_Sched_copy(redbuf-(unsigned long)handle->tmpbuf, true, recvcounts[0], datatype, recvbuf, false, recvcounts[0], datatype, schedule); if (NBC_OK != res) { free(handle->tmpbuf); printf("Error in NBC_Sched_copy() (%i)\n", res); return res; } } /*NBC_PRINT_SCHED(*schedule);*/ res = NBC_Sched_commit(schedule); if (NBC_OK != res) { free(handle->tmpbuf); printf("Error in NBC_Sched_commit() (%i)\n", res); return res; } res = NBC_Start(handle, schedule); if (NBC_OK != res) { free(handle->tmpbuf); printf("Error in NBC_Start() (%i)\n", res); return res; } /* tmpbuf is freed with the handle */ return NBC_OK; }
static inline int a2a_sched_diss(int rank, int p, MPI_Aint sndext, MPI_Aint rcvext, NBC_Schedule* schedule, void* sendbuf, int sendcount, MPI_Datatype sendtype, void* recvbuf, int recvcount, MPI_Datatype recvtype, MPI_Comm comm, NBC_Handle *handle) { int res, i, r, speer, rpeer, datasize, offset, virtp; char *rbuf, *rtmpbuf, *stmpbuf; res = NBC_OK; if(p < 2) return res; if(NBC_Type_intrinsic(sendtype)) { datasize = sndext*sendcount; } else { res = MPI_Pack_size(sendcount, sendtype, comm, &datasize); if (MPI_SUCCESS != res) { printf("MPI Error in MPI_Pack_size() (%i)\n", res); return res; } } /* allocate temporary buffers */ if(p % 2 == 0) { rtmpbuf = (char*)handle->tmpbuf+datasize*p; stmpbuf = (char*)handle->tmpbuf+datasize*(p+p/2); } else { /* we cannot divide p by two, so alloc more to be safe ... */ virtp = (p/2+1)*2; rtmpbuf = (char*)handle->tmpbuf+datasize*p; stmpbuf = (char*)handle->tmpbuf+datasize*(p+virtp/2); } /* phase 2 - communicate */ /*printf("[%i] temp buffer is at %lu of size %i, maxround: %i\n", rank, (unsigned long)handle->tmpbuf, (int)datasize*p*(1<<maxround), maxround);*/ for(r = 1; r < p; r<<=1) { offset = 0; for(i=1; i<p; i++) { /* test if bit r is set in rank number i */ if((i&r) == r) { /* copy data to sendbuffer (2nd copy) - could be avoided using iovecs */ /*printf("[%i] round %i: copying element %i to buffer %lu\n", rank, r, i, (unsigned long)(stmpbuf+offset));*/ NBC_Sched_copy((void*)(long)(i*datasize), true, datasize, MPI_BYTE, stmpbuf+offset-(unsigned long)handle->tmpbuf, true, datasize, MPI_BYTE, schedule); offset += datasize; } } speer = ( rank + r) % p; /* add p because modulo does not work with negative values */ rpeer = ((rank - r)+p) % p; /*printf("[%i] receiving %i bytes from host %i into rbuf %lu\n", rank, offset, rpeer, (unsigned long)rtmpbuf);*/ res = NBC_Sched_recv(rtmpbuf-(unsigned long)handle->tmpbuf, true, offset, MPI_BYTE, rpeer, schedule); if (NBC_OK != res) { printf("Error in NBC_Sched_recv() (%i)\n", res); return res; } /*printf("[%i] sending %i bytes to host %i from sbuf %lu\n", rank, offset, speer, (unsigned long)stmpbuf);*/ res = NBC_Sched_send(stmpbuf-(unsigned long)handle->tmpbuf, true, offset, MPI_BYTE, speer, schedule); if (NBC_OK != res) { printf("Error in NBC_Sched_send() (%i)\n", res); return res; } res = NBC_Sched_barrier(schedule); if (NBC_OK != res) { printf("Error in NBC_Sched_barrier() (%i)\n", res); return res; } /* unpack from buffer */ offset = 0; for(i=1; i<p; i++) { /* test if bit r is set in rank number i */ if((i&r) == r) { /* copy data to tmpbuffer (3rd copy) - could be avoided using iovecs */ NBC_Sched_copy(rtmpbuf+offset-(unsigned long)handle->tmpbuf, true, datasize, MPI_BYTE, (void*)(long)(i*datasize), true, datasize, MPI_BYTE, schedule); offset += datasize; } } } /* phase 3 - reorder - data is now in wrong order in handle->tmpbuf - * reorder it into recvbuf */ for(i=0; i<p; i++) { rbuf = (char*)recvbuf+((rank-i+p)%p)*recvcount*rcvext; res = NBC_Sched_unpack((void*)(long)(i*datasize), true, recvcount, recvtype, rbuf, false, schedule); if (NBC_OK != res) { printf("MPI Error in NBC_Sched_pack() (%i)\n", res); return res; } } return NBC_OK; }
/* linear iexscan * working principle: * 1. each node (but node 0) receives from left neigbor * 2. performs op * 3. all but rank p-1 do sends to it's right neigbor and exits * */ int ompi_coll_libnbc_iexscan(const void* sendbuf, void* recvbuf, int count, MPI_Datatype datatype, MPI_Op op, struct ompi_communicator_t *comm, ompi_request_t ** request, struct mca_coll_base_module_2_1_0_t *module) { int rank, p, res; MPI_Aint ext; NBC_Schedule *schedule; #ifdef NBC_CACHE_SCHEDULE NBC_Scan_args *args, *found, search; #endif char inplace; NBC_Handle *handle; ompi_coll_libnbc_module_t *libnbc_module = (ompi_coll_libnbc_module_t*) module; NBC_IN_PLACE(sendbuf, recvbuf, inplace); rank = ompi_comm_rank (comm); p = ompi_comm_size (comm); res = ompi_datatype_type_extent(datatype, &ext); if (MPI_SUCCESS != res) { NBC_Error("MPI Error in ompi_datatype_type_extent() (%i)", res); return res; } res = NBC_Init_handle(comm, &handle, libnbc_module); if (OPAL_UNLIKELY(OMPI_SUCCESS != res)) { return res; } if (inplace && rank < p - 1) { /* need more buffer space for the inplace case */ handle->tmpbuf = malloc(ext * count * 2); } else { handle->tmpbuf = malloc(ext * count); } if (handle->tmpbuf == NULL) { NBC_Return_handle (handle); return OMPI_ERR_OUT_OF_RESOURCE; } #ifdef NBC_CACHE_SCHEDULE /* search schedule in communicator specific tree */ search.sendbuf = sendbuf; search.recvbuf = recvbuf; search.count = count; search.datatype = datatype; search.op = op; found = (NBC_Scan_args *) hb_tree_search ((hb_tree *) libnbc_module->NBC_Dict[NBC_EXSCAN], &search); if (NULL == found) { #endif schedule = OBJ_NEW(NBC_Schedule); if (OPAL_UNLIKELY(NULL == schedule)) { NBC_Return_handle (handle); return OMPI_ERR_OUT_OF_RESOURCE; } /* make sure the schedule is released with the handle on error */ handle->schedule = schedule; if (rank != 0) { if (inplace && rank < p - 1) { /* if sendbuf == recvbuf do not clobber the send buffer until it has been combined * with the incoming data. */ res = NBC_Sched_recv ((void *) (ext * count), true, count, datatype, rank-1, schedule, false); } else { res = NBC_Sched_recv (recvbuf, false, count, datatype, rank-1, schedule, false); } if (OPAL_UNLIKELY(OMPI_SUCCESS != res)) { NBC_Return_handle (handle); return res; } if (rank < p - 1) { /* we have to wait until we have the data */ res = NBC_Sched_barrier(schedule); if (OPAL_UNLIKELY(OMPI_SUCCESS != res)) { NBC_Return_handle (handle); return res; } /* perform the reduce in my temporary buffer */ /* this cannot be done until handle->tmpbuf is unused :-( so barrier after */ if (inplace) { res = NBC_Sched_op (0, true, sendbuf, false, (void *)(ext * count), true, count, datatype, op, schedule, true); } else { res = NBC_Sched_op (0, true, sendbuf, false, recvbuf, false, count, datatype, op, schedule, true); } if (OPAL_UNLIKELY(OMPI_SUCCESS != res)) { NBC_Return_handle (handle); return res; } /* send reduced data onward */ res = NBC_Sched_send (0, true, count, datatype, rank + 1, schedule, false); if (OPAL_UNLIKELY(OMPI_SUCCESS != res)) { NBC_Return_handle (handle); return res; } if (inplace) { /* copy the received data into the receive buffer */ res = NBC_Sched_copy ((void *)(ext * count), true, count, datatype, recvbuf, false, count, datatype, schedule, false); if (OPAL_UNLIKELY(OMPI_SUCCESS != res)) { NBC_Return_handle (handle); return res; } } } } else if (p > 1) { res = NBC_Sched_send (sendbuf, false, count, datatype, 1, schedule, false); if (OPAL_UNLIKELY(OMPI_SUCCESS != res)) { NBC_Return_handle (handle); return res; } } res = NBC_Sched_commit(schedule); if (OPAL_UNLIKELY(OMPI_SUCCESS != res)) { NBC_Return_handle (handle); return res; } #ifdef NBC_CACHE_SCHEDULE /* save schedule to tree */ args = (NBC_Scan_args *) malloc (sizeof (args)); if (NULL != args) { args->sendbuf = sendbuf; args->recvbuf = recvbuf; args->count = count; args->datatype = datatype; args->op = op; args->schedule = schedule; res = hb_tree_insert ((hb_tree *) libnbc_module->NBC_Dict[NBC_EXSCAN], args, args, 0); if (0 == res) { OBJ_RETAIN(schedule); /* increase number of elements for A2A */ if (++libnbc_module->NBC_Dict_size[NBC_EXSCAN] > NBC_SCHED_DICT_UPPER) { NBC_SchedCache_dictwipe ((hb_tree *) libnbc_module->NBC_Dict[NBC_EXSCAN], &libnbc_module->NBC_Dict_size[NBC_EXSCAN]); } } else { NBC_Error("error in dict_insert() (%i)", res); free (args); } } } else { /* found schedule */ schedule = found->schedule; OBJ_RETAIN(schedule); } #endif res = NBC_Start (handle, schedule); if (OPAL_UNLIKELY(OMPI_SUCCESS != res)) { NBC_Return_handle (handle); return res; } *request = (ompi_request_t *) handle; /* tmpbuf is freed with the handle */ return OMPI_SUCCESS; }
int NBC_Ineighbor_alltoallw(void *sbuf, int *scounts, MPI_Datatype *stypes, void *rbuf, int *rcounts, MPI_Datatype *rtypes, MPI_Comm comm, NBC_Handle* handle) { int rank, size, res, worldsize, i; MPI_Aint *sndexts, *rcvexts; double t[10]; t[0] = PMPI_Wtime(); res = NBC_Init_handle(handle, comm); if(res != NBC_OK) { printf("Error in NBC_Init_handle(%i)\n", res); return res; } res = MPI_Comm_size(comm, &size); if (MPI_SUCCESS != res) { printf("MPI Error in MPI_Comm_size() (%i)\n", res); return res; } res = MPI_Comm_size(MPI_COMM_WORLD, &worldsize); if (MPI_SUCCESS != res) { printf("MPI Error in MPI_Comm_size() (%i)\n", res); return res; } res = MPI_Comm_rank(comm, &rank); if (MPI_SUCCESS != res) { printf("MPI Error in MPI_Comm_rank() (%i)\n", res); return res; } t[1] = PMPI_Wtime(); char inplace; NBC_Schedule *schedule; #ifdef NBC_CACHE_SCHEDULE NBC_Ineighbor_alltoallw_args *args, *found, search; #endif NBC_IN_PLACE(sbuf, rbuf, inplace); handle->tmpbuf=NULL; #ifdef NBC_CACHE_SCHEDULE /* search schedule in communicator specific tree */ search.sbuf=sbuf; search.scount=scount; search.stype=stype; search.rbuf=rbuf; search.rcount=rcount; search.rtype=rtype; found = (NBC_Ineighbor_alltoallw_args*)hb_tree_search((hb_tree*)handle->comminfo->NBC_Dict[NBC_NEIGHBOR_ALLTOALLW], &search); if(found == NULL) { #endif schedule = (NBC_Schedule*)malloc(sizeof(NBC_Schedule)); res = NBC_Sched_create(schedule); if(res != NBC_OK) { printf("Error in NBC_Sched_create, res = %i\n", res); return res; } { int indegree, outdegree, weighted, *srcs, *dsts, i; res = NBC_Comm_neighbors_count(comm, &indegree, &outdegree, &weighted); if(res != NBC_OK) return res; srcs = (int*)malloc(sizeof(int)*indegree); dsts = (int*)malloc(sizeof(int)*outdegree); sndexts = (MPI_Aint*)malloc(sizeof(MPI_Aint)*outdegree); for(i=0; i<outdegree; ++i) { res = MPI_Type_extent(stypes[i], &sndexts[i]); if (MPI_SUCCESS != res) { printf("MPI Error in MPI_Type_extent() (%i)\n", res); return res; } } rcvexts = (MPI_Aint*)malloc(sizeof(MPI_Aint)*indegree); for(i=0; i<indegree; ++i) { res = MPI_Type_extent(rtypes[i], &rcvexts[i]); if (MPI_SUCCESS != res) { printf("MPI Error in MPI_Type_extent() (%i)\n", res); return res; } } res = NBC_Comm_neighbors(comm, indegree, srcs, MPI_UNWEIGHTED, outdegree, dsts, MPI_UNWEIGHTED); if(res != NBC_OK) return res; if(inplace) { /* we need an extra buffer to be deadlock-free */ int sumrbytes=0; int offset=0; for(i=0; i<indegree; ++i) sumrbytes += rcounts[i]*rcvexts[i]; handle->tmpbuf = malloc(sumrbytes); for(i = 0; i < indegree; i++) { res = NBC_Sched_recv((char*)0+offset, true, rcounts[i], rtypes[i], srcs[i], schedule); if (NBC_OK != res) { printf("Error in NBC_Sched_recv() (%i)\n", res); return res; } offset += rcounts[i]*rcvexts[i]; } offset=0; for(i = 0; i < outdegree; i++) { res = NBC_Sched_send((char*)sbuf+offset, false, scounts[i], stypes[i], dsts[i], schedule); if (NBC_OK != res) { printf("Error in NBC_Sched_send() (%i)\n", res); return res; } offset += scounts[i]*sndexts[i]; } /* unpack from buffer */ offset=0; for(i = 0; i < indegree; i++) { res = NBC_Sched_barrier(schedule); if (NBC_OK != res) { printf("Error in NBC_Sched_barrier() (%i)\n", res); return res; } res = NBC_Sched_copy((char*)0+offset, true, rcounts[i], rtypes[i], (char*)rbuf+offset, false, rcounts[i], rtypes[i], schedule); if (NBC_OK != res) { printf("Error in NBC_Sched_copy() (%i)\n", res); return res; } offset += rcounts[i]*rcvexts[i]; } } else { /* non INPLACE case */ /* simply loop over neighbors and post send/recv operations */ int offset=0; for(i = 0; i < indegree; i++) { res = NBC_Sched_recv((char*)rbuf+offset, false, rcounts[i], rtypes[i], srcs[i], schedule); if (NBC_OK != res) { printf("Error in NBC_Sched_recv() (%i)\n", res); return res; } offset += rcounts[i]*rcvexts[i]; } offset = 0; for(i = 0; i < outdegree; i++) { res = NBC_Sched_send((char*)sbuf+offset, false, scounts[i], stypes[i], dsts[i], schedule); if (NBC_OK != res) { printf("Error in NBC_Sched_send() (%i)\n", res); return res; } offset += scounts[i]*sndexts[i]; } } } res = NBC_Sched_commit(schedule); if (NBC_OK != res) { printf("Error in NBC_Sched_commit() (%i)\n", res); return res; } #ifdef NBC_CACHE_SCHEDULE /* save schedule to tree */ args = (NBC_Ineighbor_alltoallw_args*)malloc(sizeof(NBC_Ineighbor_alltoallw_args)); args->sbuf=sbuf; args->scount=scount; args->stype=stype; args->rbuf=rbuf; args->rcount=rcount; args->rtype=rtype; args->schedule=schedule; res = hb_tree_insert ((hb_tree*)handle->comminfo->NBC_Dict[NBC_NEIGHBOR_ALLTOALLW], args, args, 0); if(res != 0) printf("error in dict_insert() (%i)\n", res); /* increase number of elements for A2A */ if(++handle->comminfo->NBC_Dict_size[NBC_NEIGHBOR_ALLTOALLW] > NBC_SCHED_DICT_UPPER) { NBC_SchedCache_dictwipe((hb_tree*)handle->comminfo->NBC_Dict[NBC_NEIGHBOR_ALLTOALLW], &handle->comminfo->NBC_Dict_size[NBC_NEIGHBOR_ALLTOALLW]); } } else { /* found schedule */ schedule=found->schedule; } #endif res = NBC_Start(handle, schedule); if (NBC_OK != res) { printf("Error in NBC_Start() (%i)\n", res); return res; } return NBC_OK; }
static int nbc_allgather_init(const void* sendbuf, int sendcount, MPI_Datatype sendtype, void* recvbuf, int recvcount, MPI_Datatype recvtype, struct ompi_communicator_t *comm, ompi_request_t ** request, struct mca_coll_base_module_2_3_0_t *module, bool persistent) { int rank, p, res; MPI_Aint rcvext; NBC_Schedule *schedule; char *rbuf, inplace; #ifdef NBC_CACHE_SCHEDULE NBC_Allgather_args *args, *found, search; #endif enum { NBC_ALLGATHER_LINEAR, NBC_ALLGATHER_RDBL} alg; ompi_coll_libnbc_module_t *libnbc_module = (ompi_coll_libnbc_module_t*) module; NBC_IN_PLACE(sendbuf, recvbuf, inplace); rank = ompi_comm_rank (comm); p = ompi_comm_size (comm); int is_commsize_pow2 = !(p & (p - 1)); if (libnbc_iallgather_algorithm == 0) { alg = NBC_ALLGATHER_LINEAR; } else { /* user forced dynamic decision */ if (libnbc_iallgather_algorithm == 1) { alg = NBC_ALLGATHER_LINEAR; } else if (libnbc_iallgather_algorithm == 2 && is_commsize_pow2) { alg = NBC_ALLGATHER_RDBL; } else { alg = NBC_ALLGATHER_LINEAR; } } res = ompi_datatype_type_extent(recvtype, &rcvext); if (MPI_SUCCESS != res) { return res; } if (inplace) { sendtype = recvtype; sendcount = recvcount; } else if (!persistent) { /* for persistent, the copy must be scheduled */ /* copy my data to receive buffer */ rbuf = (char *) recvbuf + rank * recvcount * rcvext; res = NBC_Copy (sendbuf, sendcount, sendtype, rbuf, recvcount, recvtype, comm); if (OPAL_UNLIKELY(OMPI_SUCCESS != res)) { return res; } } if (1 == p && (!persistent || inplace)) { return nbc_get_noop_request(persistent, request); } #ifdef NBC_CACHE_SCHEDULE /* search schedule in communicator specific tree */ search.sendbuf = sendbuf; search.sendcount = sendcount; search.sendtype = sendtype; search.recvbuf = recvbuf; search.recvcount = recvcount; search.recvtype = recvtype; found = (NBC_Allgather_args *) hb_tree_search ((hb_tree*)libnbc_module->NBC_Dict[NBC_ALLGATHER], &search); if (NULL == found) { #endif schedule = OBJ_NEW(NBC_Schedule); if (OPAL_UNLIKELY(NULL == schedule)) { return OMPI_ERR_OUT_OF_RESOURCE; } if (persistent && !inplace) { /* for nonblocking, data has been copied already */ /* copy my data to receive buffer (= send buffer of NBC_Sched_send) */ rbuf = (char *)recvbuf + rank * recvcount * rcvext; res = NBC_Sched_copy((void *)sendbuf, false, sendcount, sendtype, rbuf, false, recvcount, recvtype, schedule, true); if (OPAL_UNLIKELY(OMPI_SUCCESS != res)) { OBJ_RELEASE(schedule); return res; } } switch (alg) { case NBC_ALLGATHER_LINEAR: res = allgather_sched_linear(rank, p, schedule, sendbuf, sendcount, sendtype, recvbuf, recvcount, recvtype); break; case NBC_ALLGATHER_RDBL: res = allgather_sched_recursivedoubling(rank, p, schedule, sendbuf, sendcount, sendtype, recvbuf, recvcount, recvtype); break; } if (OPAL_UNLIKELY(OMPI_SUCCESS != res)) { OBJ_RELEASE(schedule); return res; } res = NBC_Sched_commit(schedule); if (OPAL_UNLIKELY(OMPI_SUCCESS != res)) { OBJ_RELEASE(schedule); return res; } #ifdef NBC_CACHE_SCHEDULE /* save schedule to tree */ args = (NBC_Allgather_args *) malloc (sizeof (args)); args->sendbuf = sendbuf; args->sendcount = sendcount; args->sendtype = sendtype; args->recvbuf = recvbuf; args->recvcount = recvcount; args->recvtype = recvtype; args->schedule = schedule; res = hb_tree_insert ((hb_tree *) libnbc_module->NBC_Dict[NBC_ALLGATHER], args, args, 0); if (res != 0) { free (args); } else { OBJ_RETAIN(schedule); } /* increase number of elements for A2A */ if (++libnbc_module->NBC_Dict_size[NBC_ALLGATHER] > NBC_SCHED_DICT_UPPER) { NBC_SchedCache_dictwipe ((hb_tree *) libnbc_module->NBC_Dict[NBC_ALLGATHER], &libnbc_module->NBC_Dict_size[NBC_ALLGATHER]); } } else { /* found schedule */ schedule = found->schedule; OBJ_RETAIN(schedule); } #endif res = NBC_Schedule_request(schedule, comm, libnbc_module, persistent, request, NULL); if (OPAL_UNLIKELY(OMPI_SUCCESS != res)) { OBJ_RELEASE(schedule); return res; } return OMPI_SUCCESS; }
/* simple linear Alltoallv */ static int nbc_alltoallv_init(const void* sendbuf, const int *sendcounts, const int *sdispls, MPI_Datatype sendtype, void* recvbuf, const int *recvcounts, const int *rdispls, MPI_Datatype recvtype, struct ompi_communicator_t *comm, ompi_request_t ** request, struct mca_coll_base_module_2_3_0_t *module, bool persistent) { int rank, p, res; MPI_Aint sndext, rcvext; NBC_Schedule *schedule; char *rbuf, *sbuf, inplace; ptrdiff_t gap = 0, span; void * tmpbuf = NULL; ompi_coll_libnbc_module_t *libnbc_module = (ompi_coll_libnbc_module_t*) module; NBC_IN_PLACE(sendbuf, recvbuf, inplace); rank = ompi_comm_rank (comm); p = ompi_comm_size (comm); res = ompi_datatype_type_extent (recvtype, &rcvext); if (MPI_SUCCESS != res) { NBC_Error("MPI Error in ompi_datatype_type_extent() (%i)", res); return res; } /* copy data to receivbuffer */ if (inplace) { int count = 0; for (int i = 0; i < p; i++) { if (recvcounts[i] > count) { count = recvcounts[i]; } } span = opal_datatype_span(&recvtype->super, count, &gap); if (OPAL_UNLIKELY(0 == span)) { return nbc_get_noop_request(persistent, request); } tmpbuf = malloc(span); if (OPAL_UNLIKELY(NULL == tmpbuf)) { return OMPI_ERR_OUT_OF_RESOURCE; } sendcounts = recvcounts; sdispls = rdispls; } else { res = ompi_datatype_type_extent (sendtype, &sndext); if (MPI_SUCCESS != res) { NBC_Error("MPI Error in ompi_datatype_type_extent() (%i)", res); return res; } } schedule = OBJ_NEW(NBC_Schedule); if (OPAL_UNLIKELY(NULL == schedule)) { free(tmpbuf); return OMPI_ERR_OUT_OF_RESOURCE; } if (!inplace && sendcounts[rank] != 0) { rbuf = (char *) recvbuf + rdispls[rank] * rcvext; sbuf = (char *) sendbuf + sdispls[rank] * sndext; res = NBC_Sched_copy (sbuf, false, sendcounts[rank], sendtype, rbuf, false, recvcounts[rank], recvtype, schedule, false); if (OPAL_UNLIKELY(OMPI_SUCCESS != res)) { OBJ_RELEASE(schedule); return res; } } if (inplace) { res = a2av_sched_inplace(rank, p, schedule, recvbuf, recvcounts, rdispls, rcvext, recvtype, gap); } else { res = a2av_sched_linear(rank, p, schedule, sendbuf, sendcounts, sdispls, sndext, sendtype, recvbuf, recvcounts, rdispls, rcvext, recvtype); } if (OPAL_UNLIKELY(OMPI_SUCCESS != res)) { OBJ_RELEASE(schedule); free(tmpbuf); return res; } res = NBC_Sched_commit (schedule); if (OPAL_UNLIKELY(OMPI_SUCCESS != res)) { OBJ_RELEASE(schedule); free(tmpbuf); return res; } res = NBC_Schedule_request(schedule, comm, libnbc_module, persistent, request, tmpbuf); if (OPAL_UNLIKELY(OMPI_SUCCESS != res)) { OBJ_RELEASE(schedule); free(tmpbuf); return res; } return OMPI_SUCCESS; }
static inline int a2av_sched_inplace(int rank, int p, NBC_Schedule *schedule, void *buf, const int *counts, const int *displs, MPI_Aint ext, MPI_Datatype type, ptrdiff_t gap) { int res; for (int i = 1; i < (p+1)/2; i++) { int speer = (rank + i) % p; int rpeer = (rank + p - i) % p; char *sbuf = (char *) buf + displs[speer] * ext; char *rbuf = (char *) buf + displs[rpeer] * ext; if (0 != counts[rpeer]) { res = NBC_Sched_copy (rbuf, false, counts[rpeer], type, (void *)(-gap), true, counts[rpeer], type, schedule, true); if (OPAL_UNLIKELY(OMPI_SUCCESS != res)) { return res; } } if (0 != counts[speer]) { res = NBC_Sched_send (sbuf, false , counts[speer], type, speer, schedule, false); if (OPAL_UNLIKELY(OMPI_SUCCESS != res)) { return res; } } if (0 != counts[rpeer]) { res = NBC_Sched_recv (rbuf, false , counts[rpeer], type, rpeer, schedule, true); if (OPAL_UNLIKELY(OMPI_SUCCESS != res)) { return res; } } if (0 != counts[rpeer]) { res = NBC_Sched_send ((void *)(-gap), true, counts[rpeer], type, rpeer, schedule, false); if (OPAL_UNLIKELY(OMPI_SUCCESS != res)) { return res; } } if (0 != counts[speer]) { res = NBC_Sched_recv (sbuf, false, counts[speer], type, speer, schedule, true); if (OPAL_UNLIKELY(OMPI_SUCCESS != res)) { return res; } } } if (0 == (p%2)) { int peer = (rank + p/2) % p; char *tbuf = (char *) buf + displs[peer] * ext; res = NBC_Sched_copy (tbuf, false, counts[peer], type, (void *)(-gap), true, counts[peer], type, schedule, true); if (OPAL_UNLIKELY(OMPI_SUCCESS != res)) { return res; } if (0 != counts[peer]) { res = NBC_Sched_send ((void *)(-gap), true , counts[peer], type, peer, schedule, false); if (OPAL_UNLIKELY(OMPI_SUCCESS != res)) { return res; } res = NBC_Sched_recv (tbuf, false , counts[peer], type, peer, schedule, true); if (OPAL_UNLIKELY(OMPI_SUCCESS != res)) { return res; } } } return OMPI_SUCCESS; }
/* simple linear Alltoallw */ static int nbc_alltoallw_init(const void* sendbuf, const int *sendcounts, const int *sdispls, struct ompi_datatype_t * const *sendtypes, void* recvbuf, const int *recvcounts, const int *rdispls, struct ompi_datatype_t * const *recvtypes, struct ompi_communicator_t *comm, ompi_request_t ** request, struct mca_coll_base_module_2_3_0_t *module, bool persistent) { int rank, p, res; NBC_Schedule *schedule; char *rbuf, *sbuf, inplace; ptrdiff_t span=0; void *tmpbuf = NULL; ompi_coll_libnbc_module_t *libnbc_module = (ompi_coll_libnbc_module_t*) module; NBC_IN_PLACE(sendbuf, recvbuf, inplace); rank = ompi_comm_rank (comm); p = ompi_comm_size (comm); /* copy data to receivbuffer */ if (inplace) { ptrdiff_t lgap, lspan; for (int i = 0; i < p; i++) { lspan = opal_datatype_span(&recvtypes[i]->super, recvcounts[i], &lgap); if (lspan > span) { span = lspan; } } if (OPAL_UNLIKELY(0 == span)) { return nbc_get_noop_request(persistent, request); } tmpbuf = malloc(span); if (OPAL_UNLIKELY(NULL == tmpbuf)) { return OMPI_ERR_OUT_OF_RESOURCE; } sendcounts = recvcounts; sdispls = rdispls; sendtypes = recvtypes; } schedule = OBJ_NEW(NBC_Schedule); if (OPAL_UNLIKELY(NULL == schedule)) { free(tmpbuf); return OMPI_ERR_OUT_OF_RESOURCE; } if (!inplace && sendcounts[rank] != 0) { rbuf = (char *) recvbuf + rdispls[rank]; sbuf = (char *) sendbuf + sdispls[rank]; res = NBC_Sched_copy(sbuf, false, sendcounts[rank], sendtypes[rank], rbuf, false, recvcounts[rank], recvtypes[rank], schedule, false); if (OPAL_UNLIKELY(OMPI_SUCCESS != res)) { return res; } } if (inplace) { res = a2aw_sched_inplace(rank, p, schedule, recvbuf, recvcounts, rdispls, recvtypes); } else { res = a2aw_sched_linear(rank, p, schedule, sendbuf, sendcounts, sdispls, sendtypes, recvbuf, recvcounts, rdispls, recvtypes); } if (OPAL_UNLIKELY(OMPI_SUCCESS != res)) { OBJ_RELEASE(schedule); free(tmpbuf); return res; } res = NBC_Sched_commit (schedule); if (OPAL_UNLIKELY(OMPI_SUCCESS != res)) { OBJ_RELEASE(schedule); free(tmpbuf); return res; } res = NBC_Schedule_request(schedule, comm, libnbc_module, persistent, request, tmpbuf); if (OPAL_UNLIKELY(OMPI_SUCCESS != res)) { OBJ_RELEASE(schedule); free(tmpbuf); return res; } return OMPI_SUCCESS; }
static inline int a2aw_sched_inplace(int rank, int p, NBC_Schedule *schedule, void *buf, const int *counts, const int *displs, struct ompi_datatype_t * const * types) { ptrdiff_t gap; int res; for (int i = 1; i < (p+1)/2; i++) { int speer = (rank + i) % p; int rpeer = (rank + p - i) % p; char *sbuf = (char *) buf + displs[speer]; char *rbuf = (char *) buf + displs[rpeer]; if (0 != counts[rpeer]) { (void)opal_datatype_span(&types[rpeer]->super, counts[rpeer], &gap); res = NBC_Sched_copy (rbuf, false, counts[rpeer], types[rpeer], (void *)(-gap), true, counts[rpeer], types[rpeer], schedule, true); if (OPAL_UNLIKELY(OMPI_SUCCESS != res)) { return res; } } if (0 != counts[speer]) { res = NBC_Sched_send (sbuf, false , counts[speer], types[speer], speer, schedule, false); if (OPAL_UNLIKELY(OMPI_SUCCESS != res)) { return res; } } if (0 != counts[rpeer]) { res = NBC_Sched_recv (rbuf, false , counts[rpeer], types[rpeer], rpeer, schedule, true); if (OPAL_UNLIKELY(OMPI_SUCCESS != res)) { return res; } } if (0 != counts[rpeer]) { res = NBC_Sched_send ((void *)(-gap), true, counts[rpeer], types[rpeer], rpeer, schedule, false); if (OPAL_UNLIKELY(OMPI_SUCCESS != res)) { return res; } } if (0 != counts[speer]) { res = NBC_Sched_recv (sbuf, false, counts[speer], types[speer], speer, schedule, true); if (OPAL_UNLIKELY(OMPI_SUCCESS != res)) { return res; } } } if (0 == (p%2)) { int peer = (rank + p/2) % p; char *tbuf = (char *) buf + displs[peer]; (void)opal_datatype_span(&types[peer]->super, counts[peer], &gap); res = NBC_Sched_copy (tbuf, false, counts[peer], types[peer], (void *)(-gap), true, counts[peer], types[peer], schedule, true); if (OPAL_UNLIKELY(OMPI_SUCCESS != res)) { return res; } res = NBC_Sched_send ((void *)(-gap), true , counts[peer], types[peer], peer, schedule, false); if (OPAL_UNLIKELY(OMPI_SUCCESS != res)) { return res; } res = NBC_Sched_recv (tbuf, false , counts[peer], types[peer], peer, schedule, true); if (OPAL_UNLIKELY(OMPI_SUCCESS != res)) { return res; } } return OMPI_SUCCESS; }
/* linear iscan * working principle: * 1. each node (but node 0) receives from left neighbor * 2. performs op * 3. all but rank p-1 do sends to it's right neighbor and exits * */ static int nbc_scan_init(const void* sendbuf, void* recvbuf, int count, MPI_Datatype datatype, MPI_Op op, struct ompi_communicator_t *comm, ompi_request_t ** request, struct mca_coll_base_module_2_3_0_t *module, bool persistent) { int rank, p, res; ptrdiff_t gap, span; NBC_Schedule *schedule; void *tmpbuf = NULL; char inplace; ompi_coll_libnbc_module_t *libnbc_module = (ompi_coll_libnbc_module_t*) module; NBC_IN_PLACE(sendbuf, recvbuf, inplace); rank = ompi_comm_rank (comm); p = ompi_comm_size (comm); #ifdef NBC_CACHE_SCHEDULE NBC_Scan_args *args, *found, search; /* search schedule in communicator specific tree */ search.sendbuf = sendbuf; search.recvbuf = recvbuf; search.count = count; search.datatype = datatype; search.op = op; found = (NBC_Scan_args *) hb_tree_search ((hb_tree *) libnbc_module->NBC_Dict[NBC_SCAN], &search); if (NULL == found) { #endif schedule = OBJ_NEW(NBC_Schedule); if (OPAL_UNLIKELY(NULL == schedule)) { return OMPI_ERR_OUT_OF_RESOURCE; } if (!inplace) { /* copy data to receivebuf */ res = NBC_Sched_copy ((void *)sendbuf, false, count, datatype, recvbuf, false, count, datatype, schedule, false); if (OPAL_UNLIKELY(OMPI_SUCCESS != res)) { OBJ_RELEASE(schedule); return res; } } if(rank != 0) { span = opal_datatype_span(&datatype->super, count, &gap); tmpbuf = malloc (span); if (NULL == tmpbuf) { OBJ_RELEASE(schedule); return OMPI_ERR_OUT_OF_RESOURCE; } /* we have to wait until we have the data */ res = NBC_Sched_recv ((void *)(-gap), true, count, datatype, rank-1, schedule, true); if (OPAL_UNLIKELY(OMPI_SUCCESS != res)) { OBJ_RELEASE(schedule); free(tmpbuf); return res; } /* perform the reduce in my local buffer */ /* this cannot be done until tmpbuf is unused :-( so barrier after the op */ res = NBC_Sched_op ((void *)(-gap), true, recvbuf, false, count, datatype, op, schedule, true); if (OPAL_UNLIKELY(OMPI_SUCCESS != res)) { OBJ_RELEASE(schedule); free(tmpbuf); return res; } } if (rank != p-1) { res = NBC_Sched_send (recvbuf, false, count, datatype, rank+1, schedule, false); if (OPAL_UNLIKELY(OMPI_SUCCESS != res)) { OBJ_RELEASE(schedule); free(tmpbuf); return res; } } res = NBC_Sched_commit (schedule); if (OPAL_UNLIKELY(OMPI_SUCCESS != res)) { OBJ_RELEASE(schedule); free(tmpbuf); return res; } #ifdef NBC_CACHE_SCHEDULE /* save schedule to tree */ args = (NBC_Scan_args *) malloc (sizeof (args)); if (NULL != args) { args->sendbuf = sendbuf; args->recvbuf = recvbuf; args->count = count; args->datatype = datatype; args->op = op; args->schedule = schedule; res = hb_tree_insert ((hb_tree *) libnbc_module->NBC_Dict[NBC_SCAN], args, args, 0); if (0 == res) { OBJ_RETAIN(schedule); /* increase number of elements for A2A */ if (++libnbc_module->NBC_Dict_size[NBC_SCAN] > NBC_SCHED_DICT_UPPER) { NBC_SchedCache_dictwipe ((hb_tree *) libnbc_module->NBC_Dict[NBC_SCAN], &libnbc_module->NBC_Dict_size[NBC_SCAN]); } } else { NBC_Error("error in dict_insert() (%i)", res); free (args); } } } else { /* found schedule */ schedule = found->schedule; OBJ_RETAIN(schedule); } #endif res = NBC_Schedule_request(schedule, comm, libnbc_module, persistent, request, tmpbuf); if (OPAL_UNLIKELY(OMPI_SUCCESS != res)) { OBJ_RELEASE(schedule); free(tmpbuf); return res; } return OMPI_SUCCESS; }