int MPIR_Ibarrier_intra(MPID_Comm *comm_ptr, MPID_Sched_t s) { int mpi_errno = MPI_SUCCESS; int size, rank, src, dst, mask; MPIU_Assert(comm_ptr->comm_kind == MPID_INTRACOMM); size = comm_ptr->local_size; rank = comm_ptr->rank; /* Trivial barriers return immediately */ if (size == 1) goto fn_exit; mask = 0x1; while (mask < size) { dst = (rank + mask) % size; src = (rank - mask + size) % size; mpi_errno = MPID_Sched_send(NULL, 0, MPI_BYTE, dst, comm_ptr, s); if (mpi_errno) MPIR_ERR_POP(mpi_errno); mpi_errno = MPID_Sched_recv(NULL, 0, MPI_BYTE, src, comm_ptr, s); if (mpi_errno) MPIR_ERR_POP(mpi_errno); mpi_errno = MPID_Sched_barrier(s); if (mpi_errno) MPIR_ERR_POP(mpi_errno); mask <<= 1; } fn_exit: return mpi_errno; fn_fail: goto fn_exit; }
int MPIR_Ialltoall_pairwise(const void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, MPID_Comm *comm_ptr, MPID_Sched_t s) { int mpi_errno = MPI_SUCCESS; int i; int src, dst, is_pof2; int rank, comm_size; MPI_Aint sendtype_extent, recvtype_extent; MPIU_Assert(sendbuf != MPI_IN_PLACE); /* we do not handle in-place */ comm_size = comm_ptr->local_size; rank = comm_ptr->rank; MPID_Datatype_get_extent_macro(sendtype, sendtype_extent); MPID_Datatype_get_extent_macro(recvtype, recvtype_extent); /* Make local copy first */ mpi_errno = MPID_Sched_copy(((char *)sendbuf + rank*sendcount*sendtype_extent), sendcount, sendtype, ((char *)recvbuf + rank*recvcount*recvtype_extent), recvcount, recvtype, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); is_pof2 = MPIU_is_pof2(comm_size, NULL); /* Do the pairwise exchanges */ for (i = 1; i < comm_size; i++) { if (is_pof2 == 1) { /* use exclusive-or algorithm */ src = dst = rank ^ i; } else { src = (rank - i + comm_size) % comm_size; dst = (rank + i) % comm_size; } mpi_errno = MPID_Sched_send(((char *)sendbuf + dst*sendcount*sendtype_extent), sendcount, sendtype, dst, comm_ptr, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); mpi_errno = MPID_Sched_recv(((char *)recvbuf + src*recvcount*recvtype_extent), recvcount, recvtype, src, comm_ptr, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); MPID_SCHED_BARRIER(s); } fn_exit: return mpi_errno; fn_fail: goto fn_exit; }
int MPIR_Ineighbor_allgatherv_default(const void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, const int recvcounts[], const int displs[], MPI_Datatype recvtype, MPID_Comm *comm_ptr, MPID_Sched_t s) { int mpi_errno = MPI_SUCCESS; int indegree, outdegree, weighted; int i, k,l; int *srcs, *dsts; int comm_size; MPI_Aint recvtype_extent; MPIU_CHKLMEM_DECL(2); comm_size = comm_ptr->local_size; MPID_Datatype_get_extent_macro(recvtype, recvtype_extent); for (i = 0; i < comm_size; ++i) { MPID_Ensure_Aint_fits_in_pointer(MPI_VOID_PTR_CAST_TO_MPI_AINT recvbuf + (displs[i] * recvtype_extent)); } mpi_errno = MPIR_Topo_canon_nhb_count(comm_ptr, &indegree, &outdegree, &weighted); if (mpi_errno) MPIU_ERR_POP(mpi_errno); MPIU_CHKLMEM_MALLOC(srcs, int *, indegree*sizeof(int), mpi_errno, "srcs"); MPIU_CHKLMEM_MALLOC(dsts, int *, outdegree*sizeof(int), mpi_errno, "dsts"); mpi_errno = MPIR_Topo_canon_nhb(comm_ptr, indegree, srcs, MPI_UNWEIGHTED, outdegree, dsts, MPI_UNWEIGHTED); if (mpi_errno) MPIU_ERR_POP(mpi_errno); for (k = 0; k < outdegree; ++k) { mpi_errno = MPID_Sched_send(sendbuf, sendcount, sendtype, dsts[k], comm_ptr, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); } for (l = 0; l < indegree; ++l) { char *rb = ((char *)recvbuf) + displs[l] * recvtype_extent; mpi_errno = MPID_Sched_recv(rb, recvcounts[l], recvtype, srcs[l], comm_ptr, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); } MPID_SCHED_BARRIER(s); fn_exit: MPIU_CHKLMEM_FREEALL(); return mpi_errno; fn_fail: goto fn_exit; }
int MPIR_Ialltoall_perm_sr(const void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, MPID_Comm *comm_ptr, MPID_Sched_t s) { int mpi_errno = MPI_SUCCESS; int i; int rank, comm_size; int ii, ss, bblock, dst; MPI_Aint sendtype_extent, recvtype_extent; MPIU_Assert(sendbuf != MPI_IN_PLACE); /* we do not handle in-place */ comm_size = comm_ptr->local_size; rank = comm_ptr->rank; MPID_Datatype_get_extent_macro(sendtype, sendtype_extent); MPID_Datatype_get_extent_macro(recvtype, recvtype_extent); bblock = MPIR_CVAR_ALLTOALL_THROTTLE; if (bblock == 0) bblock = comm_size; for (ii = 0; ii < comm_size; ii += bblock) { ss = comm_size-ii < bblock ? comm_size-ii : bblock; /* do the communication -- post ss sends and receives: */ for (i = 0; i < ss; i++) { dst = (rank+i+ii) % comm_size; mpi_errno = MPID_Sched_recv(((char *)recvbuf + dst*recvcount*recvtype_extent), recvcount, recvtype, dst, comm_ptr, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); } for (i = 0; i < ss; i++) { dst = (rank-i-ii+comm_size) % comm_size; mpi_errno = MPID_Sched_send(((char *)sendbuf + dst*sendcount*sendtype_extent), sendcount, sendtype, dst, comm_ptr, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); } /* force the (2*ss) sends/recvs above to complete before posting additional ops */ MPID_SCHED_BARRIER(s); } fn_exit: return mpi_errno; fn_fail: goto fn_exit; }
int MPIR_Ineighbor_alltoallw_default(const void *sendbuf, const int sendcounts[], const MPI_Aint sdispls[], const MPI_Datatype sendtypes[], void *recvbuf, const int recvcounts[], const MPI_Aint rdispls[], const MPI_Datatype recvtypes[], MPID_Comm *comm_ptr, MPID_Sched_t s) { int mpi_errno = MPI_SUCCESS; int indegree, outdegree, weighted; int k,l; int *srcs, *dsts; MPIU_CHKLMEM_DECL(2); mpi_errno = MPIR_Topo_canon_nhb_count(comm_ptr, &indegree, &outdegree, &weighted); if (mpi_errno) MPIU_ERR_POP(mpi_errno); MPIU_CHKLMEM_MALLOC(srcs, int *, indegree*sizeof(int), mpi_errno, "srcs"); MPIU_CHKLMEM_MALLOC(dsts, int *, outdegree*sizeof(int), mpi_errno, "dsts"); mpi_errno = MPIR_Topo_canon_nhb(comm_ptr, indegree, srcs, MPI_UNWEIGHTED, outdegree, dsts, MPI_UNWEIGHTED); if (mpi_errno) MPIU_ERR_POP(mpi_errno); for (k = 0; k < outdegree; ++k) { char *sb; MPID_Ensure_Aint_fits_in_pointer(MPI_VOID_PTR_CAST_TO_MPI_AINT sendbuf + sdispls[k]); sb = ((char *)sendbuf) + sdispls[k]; mpi_errno = MPID_Sched_send(sb, sendcounts[k], sendtypes[k], dsts[k], comm_ptr, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); } for (l = 0; l < indegree; ++l) { char *rb; MPID_Ensure_Aint_fits_in_pointer(MPI_VOID_PTR_CAST_TO_MPI_AINT recvbuf + rdispls[l]); rb = ((char *)recvbuf) + rdispls[l]; mpi_errno = MPID_Sched_recv(rb, recvcounts[l], recvtypes[l], srcs[l], comm_ptr, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); } MPID_SCHED_BARRIER(s); fn_exit: MPIU_CHKLMEM_FREEALL(); return mpi_errno; fn_fail: goto fn_exit; }
static int sched_cb_gcn_bcast(MPID_Comm * comm, int tag, void *state) { int mpi_errno = MPI_SUCCESS; struct gcn_state *st = state; if (st->gcn_cid_kind == MPID_INTERCOMM) { if (st->comm_ptr_inter->rank == 0) { mpi_errno = MPID_Sched_recv(st->ctx1, 1, MPIU_CONTEXT_ID_T_DATATYPE, 0, st->comm_ptr_inter, st->s); if (mpi_errno) MPIR_ERR_POP(mpi_errno); mpi_errno = MPID_Sched_send(st->ctx0, 1, MPIU_CONTEXT_ID_T_DATATYPE, 0, st->comm_ptr_inter, st->s); if (mpi_errno) MPIR_ERR_POP(mpi_errno); MPID_SCHED_BARRIER(st->s); } mpi_errno = st->comm_ptr->coll_fns->Ibcast_sched(st->ctx1, 1, MPIU_CONTEXT_ID_T_DATATYPE, 0, st->comm_ptr, st->s); if (mpi_errno) MPIR_ERR_POP(mpi_errno); MPID_SCHED_BARRIER(st->s); } mpi_errno = MPID_Sched_cb(&sched_cb_commit_comm, st, st->s); if (mpi_errno) MPIR_ERR_POP(mpi_errno); mpi_errno = MPID_Sched_cb(&MPIR_Sched_cb_free_buf, st, st->s); if (mpi_errno) MPIR_ERR_POP(mpi_errno); fn_fail: return mpi_errno; }
int MPIR_Igatherv(const void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, const int recvcounts[], const int displs[], MPI_Datatype recvtype, int root, MPID_Comm *comm_ptr, MPID_Sched_t s) { int mpi_errno = MPI_SUCCESS; int i; int comm_size, rank; MPI_Aint extent; int min_procs; rank = comm_ptr->rank; /* If rank == root, then I recv lots, otherwise I send */ if (((comm_ptr->comm_kind == MPID_INTRACOMM) && (root == rank)) || ((comm_ptr->comm_kind == MPID_INTERCOMM) && (root == MPI_ROOT))) { if (comm_ptr->comm_kind == MPID_INTRACOMM) comm_size = comm_ptr->local_size; else comm_size = comm_ptr->remote_size; MPID_Datatype_get_extent_macro(recvtype, extent); /* each node can make sure it is not going to overflow aint */ MPID_Ensure_Aint_fits_in_pointer(MPI_VOID_PTR_CAST_TO_MPI_AINT recvbuf + displs[rank] * extent); for (i = 0; i < comm_size; i++) { if (recvcounts[i]) { if ((comm_ptr->comm_kind == MPID_INTRACOMM) && (i == rank)) { if (sendbuf != MPI_IN_PLACE) { mpi_errno = MPID_Sched_copy(sendbuf, sendcount, sendtype, ((char *)recvbuf+displs[rank]*extent), recvcounts[rank], recvtype, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); } } else { mpi_errno = MPID_Sched_recv(((char *)recvbuf+displs[i]*extent), recvcounts[i], recvtype, i, comm_ptr, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); } } } } else if (root != MPI_PROC_NULL) { /* non-root nodes, and in the intercomm. case, non-root nodes on remote side */ if (sendcount) { /* we want local size in both the intracomm and intercomm cases because the size of the root's group (group A in the standard) is irrelevant here. */ comm_size = comm_ptr->local_size; min_procs = MPIR_PARAM_GATHERV_INTER_SSEND_MIN_PROCS; if (min_procs == -1) min_procs = comm_size + 1; /* Disable ssend */ else if (min_procs == 0) /* backwards compatibility, use default value */ MPIR_PARAM_GET_DEFAULT_INT(GATHERV_INTER_SSEND_MIN_PROCS,&min_procs); if (comm_size >= min_procs) mpi_errno = MPID_Sched_ssend(sendbuf, sendcount, sendtype, root, comm_ptr, s); else mpi_errno = MPID_Sched_send(sendbuf, sendcount, sendtype, root, comm_ptr, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); } } fn_exit: return mpi_errno; fn_fail: goto fn_exit; }
int MPIR_Iallreduce_redscat_allgather(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPID_Comm *comm_ptr, MPID_Sched_t s) { int mpi_errno = MPI_SUCCESS; int comm_size, rank, newrank, pof2, rem; int i, send_idx, recv_idx, last_idx, mask, newdst, dst, send_cnt, recv_cnt; MPI_Aint true_lb, true_extent, extent; void *tmp_buf = NULL; int *cnts, *disps; MPIR_SCHED_CHKPMEM_DECL(1); MPIU_CHKLMEM_DECL(2); /* we only support builtin datatypes for now, breaking up user types to do * the reduce-scatter is tricky */ MPIU_Assert(HANDLE_GET_KIND(op) == HANDLE_KIND_BUILTIN); comm_size = comm_ptr->local_size; rank = comm_ptr->rank; /* need to allocate temporary buffer to store incoming data*/ MPIR_Type_get_true_extent_impl(datatype, &true_lb, &true_extent); MPID_Datatype_get_extent_macro(datatype, extent); MPID_Ensure_Aint_fits_in_pointer(count * MPIR_MAX(extent, true_extent)); MPIR_SCHED_CHKPMEM_MALLOC(tmp_buf, void *, count*(MPIR_MAX(extent,true_extent)), mpi_errno, "temporary buffer"); /* adjust for potential negative lower bound in datatype */ tmp_buf = (void *)((char*)tmp_buf - true_lb); /* copy local data into recvbuf */ if (sendbuf != MPI_IN_PLACE) { mpi_errno = MPID_Sched_copy(sendbuf, count, datatype, recvbuf, count, datatype, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); MPID_SCHED_BARRIER(s); } /* find nearest power-of-two less than or equal to comm_size */ pof2 = 1; while (pof2 <= comm_size) pof2 <<= 1; pof2 >>=1; rem = comm_size - pof2; /* In the non-power-of-two case, all even-numbered processes of rank < 2*rem send their data to (rank+1). These even-numbered processes no longer participate in the algorithm until the very end. The remaining processes form a nice power-of-two. */ if (rank < 2*rem) { if (rank % 2 == 0) { /* even */ mpi_errno = MPID_Sched_send(recvbuf, count, datatype, rank+1, comm_ptr, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); MPID_SCHED_BARRIER(s); /* temporarily set the rank to -1 so that this process does not pariticipate in recursive doubling */ newrank = -1; } else { /* odd */ mpi_errno = MPID_Sched_recv(tmp_buf, count, datatype, rank-1, comm_ptr, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); MPID_SCHED_BARRIER(s); /* do the reduction on received data. since the ordering is right, it doesn't matter whether the operation is commutative or not. */ mpi_errno = MPID_Sched_reduce(tmp_buf, recvbuf, count, datatype, op, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); MPID_SCHED_BARRIER(s); /* change the rank */ newrank = rank / 2; } } else /* rank >= 2*rem */ newrank = rank - rem; if (newrank != -1) { /* for the reduce-scatter, calculate the count that each process receives and the displacement within the buffer */ /* TODO I (goodell@) believe that these counts and displacements could be * calculated directly during the loop, rather than requiring a less-scalable * "2*pof2"-sized memory allocation */ MPIU_CHKLMEM_MALLOC(cnts, int *, pof2*sizeof(int), mpi_errno, "counts"); MPIU_CHKLMEM_MALLOC(disps, int *, pof2*sizeof(int), mpi_errno, "displacements"); MPIU_Assert(count >= pof2); /* the cnts calculations assume this */ for (i=0; i<(pof2-1); i++) cnts[i] = count/pof2; cnts[pof2-1] = count - (count/pof2)*(pof2-1); disps[0] = 0; for (i=1; i<pof2; i++) disps[i] = disps[i-1] + cnts[i-1]; mask = 0x1; send_idx = recv_idx = 0; last_idx = pof2; while (mask < pof2) { newdst = newrank ^ mask; /* find real rank of dest */ dst = (newdst < rem) ? newdst*2 + 1 : newdst + rem; send_cnt = recv_cnt = 0; if (newrank < newdst) { send_idx = recv_idx + pof2/(mask*2); for (i=send_idx; i<last_idx; i++) send_cnt += cnts[i]; for (i=recv_idx; i<send_idx; i++) recv_cnt += cnts[i]; } else { recv_idx = send_idx + pof2/(mask*2); for (i=send_idx; i<recv_idx; i++) send_cnt += cnts[i]; for (i=recv_idx; i<last_idx; i++) recv_cnt += cnts[i]; } /* Send data from recvbuf. Recv into tmp_buf */ mpi_errno = MPID_Sched_recv(((char *)tmp_buf + disps[recv_idx]*extent), recv_cnt, datatype, dst, comm_ptr, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); /* sendrecv, no barrier here */ mpi_errno = MPID_Sched_send(((char *)recvbuf + disps[send_idx]*extent), send_cnt, datatype, dst, comm_ptr, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); MPID_SCHED_BARRIER(s); /* tmp_buf contains data received in this step. recvbuf contains data accumulated so far */ /* This algorithm is used only for predefined ops and predefined ops are always commutative. */ mpi_errno = MPID_Sched_reduce(((char *)tmp_buf + disps[recv_idx]*extent), ((char *)recvbuf + disps[recv_idx]*extent), recv_cnt, datatype, op, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); MPID_SCHED_BARRIER(s); /* update send_idx for next iteration */ send_idx = recv_idx; mask <<= 1; /* update last_idx, but not in last iteration because the value is needed in the allgather step below. */ if (mask < pof2) last_idx = recv_idx + pof2/mask; } /* now do the allgather */ mask >>= 1; while (mask > 0) { newdst = newrank ^ mask; /* find real rank of dest */ dst = (newdst < rem) ? newdst*2 + 1 : newdst + rem; send_cnt = recv_cnt = 0; if (newrank < newdst) { /* update last_idx except on first iteration */ if (mask != pof2/2) last_idx = last_idx + pof2/(mask*2); recv_idx = send_idx + pof2/(mask*2); for (i=send_idx; i<recv_idx; i++) send_cnt += cnts[i]; for (i=recv_idx; i<last_idx; i++) recv_cnt += cnts[i]; } else { recv_idx = send_idx - pof2/(mask*2); for (i=send_idx; i<last_idx; i++) send_cnt += cnts[i]; for (i=recv_idx; i<send_idx; i++) recv_cnt += cnts[i]; } mpi_errno = MPID_Sched_recv(((char *)recvbuf + disps[recv_idx]*extent), recv_cnt, datatype, dst, comm_ptr, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); /* sendrecv, no barrier here */ mpi_errno = MPID_Sched_send(((char *)recvbuf + disps[send_idx]*extent), send_cnt, datatype, dst, comm_ptr, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); MPID_SCHED_BARRIER(s); if (newrank > newdst) send_idx = recv_idx; mask >>= 1; } }
int MPIR_Ialltoall_inter(const void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, MPID_Comm *comm_ptr, MPID_Sched_t s) { /* Intercommunicator alltoall. We use a pairwise exchange algorithm similar to the one used in intracommunicator alltoall for long messages. Since the local and remote groups can be of different sizes, we first compute the max of local_group_size, remote_group_size. At step i, 0 <= i < max_size, each process receives from src = (rank - i + max_size) % max_size if src < remote_size, and sends to dst = (rank + i) % max_size if dst < remote_size. */ int mpi_errno = MPI_SUCCESS; int local_size, remote_size, max_size, i; MPI_Aint sendtype_extent, recvtype_extent; int src, dst, rank; char *sendaddr, *recvaddr; local_size = comm_ptr->local_size; remote_size = comm_ptr->remote_size; rank = comm_ptr->rank; /* Get extent of send and recv types */ MPID_Datatype_get_extent_macro(sendtype, sendtype_extent); MPID_Datatype_get_extent_macro(recvtype, recvtype_extent); /* Do the pairwise exchanges */ max_size = MPIR_MAX(local_size, remote_size); MPID_Ensure_Aint_fits_in_pointer(MPI_VOID_PTR_CAST_TO_MPI_AINT recvbuf + max_size*recvcount*recvtype_extent); MPID_Ensure_Aint_fits_in_pointer(MPI_VOID_PTR_CAST_TO_MPI_AINT sendbuf + max_size*sendcount*sendtype_extent); for (i = 0; i < max_size; i++) { src = (rank - i + max_size) % max_size; dst = (rank + i) % max_size; if (src >= remote_size) { src = MPI_PROC_NULL; recvaddr = NULL; } else { recvaddr = (char *)recvbuf + src*recvcount*recvtype_extent; } if (dst >= remote_size) { dst = MPI_PROC_NULL; sendaddr = NULL; } else { sendaddr = (char *)sendbuf + dst*sendcount*sendtype_extent; } mpi_errno = MPID_Sched_send(sendaddr, sendcount, sendtype, dst, comm_ptr, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); mpi_errno = MPID_Sched_recv(recvaddr, recvcount, recvtype, src, comm_ptr, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); MPID_SCHED_BARRIER(s); } fn_exit: return mpi_errno; fn_fail: goto fn_exit; }
int MPIR_Ialltoall_inplace(const void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, MPID_Comm *comm_ptr, MPID_Sched_t s) { int mpi_errno = MPI_SUCCESS; void *tmp_buf = NULL; int i, j; int rank, comm_size; int nbytes, recvtype_size; MPI_Aint recvtype_extent; int peer; MPIR_SCHED_CHKPMEM_DECL(1); MPIU_Assert(sendbuf == MPI_IN_PLACE); if (recvcount == 0) goto fn_exit; comm_size = comm_ptr->local_size; rank = comm_ptr->rank; MPID_Datatype_get_size_macro(recvtype, recvtype_size); MPID_Datatype_get_extent_macro(recvtype, recvtype_extent); nbytes = recvtype_size * recvcount; MPIR_SCHED_CHKPMEM_MALLOC(tmp_buf, void *, nbytes, mpi_errno, "tmp_buf"); for (i = 0; i < comm_size; ++i) { /* start inner loop at i to avoid re-exchanging data */ for (j = i; j < comm_size; ++j) { if (rank == i && rank == j) { /* no need to "sendrecv_replace" for ourselves */ } else if (rank == i || rank == j) { if (rank == i) peer = j; else peer = i; /* pack to tmp_buf */ mpi_errno = MPID_Sched_copy(((char *)recvbuf + peer*recvcount*recvtype_extent), recvcount, recvtype, tmp_buf, nbytes, MPI_BYTE, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); MPID_SCHED_BARRIER(s); /* now simultaneously send from tmp_buf and recv to recvbuf */ mpi_errno = MPID_Sched_send(tmp_buf, nbytes, MPI_BYTE, peer, comm_ptr, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); mpi_errno = MPID_Sched_recv(((char *)recvbuf + peer*recvcount*recvtype_extent), recvcount, recvtype, peer, comm_ptr, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); MPID_SCHED_BARRIER(s); } } } MPIR_SCHED_CHKPMEM_COMMIT(s); fn_exit: return mpi_errno; fn_fail: MPIR_SCHED_CHKPMEM_REAP(s); goto fn_exit; }
int MPIR_Ialltoall_bruck(const void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, MPID_Comm *comm_ptr, MPID_Sched_t s) { int mpi_errno = MPI_SUCCESS; int i; int nbytes, recvtype_size, recvbuf_extent, newtype_size; int rank, comm_size; void *tmp_buf = NULL; MPI_Aint sendtype_extent, recvtype_extent, recvtype_true_lb, recvtype_true_extent; int pof2, dst, src; int count, block; MPI_Datatype newtype; int *displs; MPIU_CHKLMEM_DECL(1); /* displs */ MPIR_SCHED_CHKPMEM_DECL(2); /* tmp_buf (2x) */ MPIU_Assert(sendbuf != MPI_IN_PLACE); /* we do not handle in-place */ comm_size = comm_ptr->local_size; rank = comm_ptr->rank; MPID_Datatype_get_extent_macro(sendtype, sendtype_extent); MPID_Datatype_get_size_macro(recvtype, recvtype_size); MPID_Datatype_get_extent_macro(recvtype, recvtype_extent); /* allocate temporary buffer */ /* must be same size as entire recvbuf for Phase 3 */ nbytes = recvtype_size * recvcount * comm_size; MPIR_SCHED_CHKPMEM_MALLOC(tmp_buf, void *, nbytes, mpi_errno, "tmp_buf"); /* Do Phase 1 of the algorithim. Shift the data blocks on process i * upwards by a distance of i blocks. Store the result in recvbuf. */ mpi_errno = MPID_Sched_copy(((char *) sendbuf + rank*sendcount*sendtype_extent), (comm_size - rank)*sendcount, sendtype, recvbuf, (comm_size - rank)*recvcount, recvtype, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); mpi_errno = MPID_Sched_copy(sendbuf, rank*sendcount, sendtype, ((char *) recvbuf + (comm_size-rank)*recvcount*recvtype_extent), rank*recvcount, recvtype, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); MPID_SCHED_BARRIER(s); /* Input data is now stored in recvbuf with datatype recvtype */ /* Now do Phase 2, the communication phase. It takes ceiling(lg p) steps. In each step i, each process sends to rank+2^i and receives from rank-2^i, and exchanges all data blocks whose ith bit is 1. */ /* allocate displacements array for indexed datatype used in communication */ MPIU_CHKLMEM_MALLOC(displs, int *, comm_size * sizeof(int), mpi_errno, "displs"); pof2 = 1; while (pof2 < comm_size) { dst = (rank + pof2) % comm_size; src = (rank - pof2 + comm_size) % comm_size; /* Exchange all data blocks whose ith bit is 1 */ /* Create an indexed datatype for the purpose */ count = 0; for (block=1; block<comm_size; block++) { if (block & pof2) { displs[count] = block * recvcount; count++; } } mpi_errno = MPIR_Type_create_indexed_block_impl(count, recvcount, displs, recvtype, &newtype); if (mpi_errno) MPIU_ERR_POP(mpi_errno); mpi_errno = MPIR_Type_commit_impl(&newtype); if (mpi_errno) MPIU_ERR_POP(mpi_errno); MPID_Datatype_get_size_macro(newtype, newtype_size); /* we will usually copy much less than nbytes */ mpi_errno = MPID_Sched_copy(recvbuf, 1, newtype, tmp_buf, newtype_size, MPI_BYTE, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); MPID_SCHED_BARRIER(s); /* now send and recv in parallel */ mpi_errno = MPID_Sched_send(tmp_buf, newtype_size, MPI_BYTE, dst, comm_ptr, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); mpi_errno = MPID_Sched_recv(recvbuf, 1, newtype, src, comm_ptr, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); MPID_SCHED_BARRIER(s); MPIR_Type_free_impl(&newtype); pof2 *= 2; } /* Phase 3: Rotate blocks in recvbuf upwards by (rank + 1) blocks. Need * a temporary buffer of the same size as recvbuf. */ /* get true extent of recvtype */ MPIR_Type_get_true_extent_impl(recvtype, &recvtype_true_lb, &recvtype_true_extent); recvbuf_extent = recvcount * comm_size * (MPIR_MAX(recvtype_true_extent, recvtype_extent)); /* not a leak, old tmp_buf value is still tracked by CHKPMEM macros */ MPIR_SCHED_CHKPMEM_MALLOC(tmp_buf, void *, recvbuf_extent, mpi_errno, "tmp_buf"); /* adjust for potential negative lower bound in datatype */ tmp_buf = (void *)((char*)tmp_buf - recvtype_true_lb); mpi_errno = MPID_Sched_copy(((char *) recvbuf + (rank+1)*recvcount*recvtype_extent), (comm_size - rank - 1)*recvcount, recvtype, tmp_buf, (comm_size - rank - 1)*recvcount, recvtype, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); mpi_errno = MPID_Sched_copy(recvbuf, (rank+1)*recvcount, recvtype, ((char *) tmp_buf + (comm_size-rank-1)*recvcount*recvtype_extent), (rank+1)*recvcount, recvtype, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); MPID_SCHED_BARRIER(s); /* Blocks are in the reverse order now (comm_size-1 to 0). * Reorder them to (0 to comm_size-1) and store them in recvbuf. */ for (i = 0; i < comm_size; i++){ mpi_errno = MPID_Sched_copy(((char *) tmp_buf + i*recvcount*recvtype_extent), recvcount, recvtype, ((char *) recvbuf + (comm_size-i-1)*recvcount*recvtype_extent), recvcount, recvtype, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); } MPIR_SCHED_CHKPMEM_COMMIT(s); fn_exit: MPIU_CHKLMEM_FREEALL(); return mpi_errno; fn_fail: MPIR_SCHED_CHKPMEM_REAP(s); goto fn_exit; }
int MPIR_Iallgatherv_rec_dbl(const void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, const int recvcounts[], const int displs[], MPI_Datatype recvtype, MPID_Comm *comm_ptr, MPID_Sched_t s) { int mpi_errno = MPI_SUCCESS; int comm_size, rank, i, j, k; int curr_count, send_offset, incoming_count, recv_offset; int mask, dst, total_count, position, offset, my_tree_root, dst_tree_root; MPI_Aint recvtype_extent, recvtype_true_extent, recvtype_true_lb; void *tmp_buf = NULL; int is_homogeneous ATTRIBUTE((unused)); MPIR_SCHED_CHKPMEM_DECL(1); comm_size = comm_ptr->local_size; rank = comm_ptr->rank; is_homogeneous = 1; #ifdef MPID_HAS_HETERO if (comm_ptr->is_hetero) is_homogeneous = 0; #endif MPIU_Assert(is_homogeneous); /* we only handle the homogeneous for now */ /* need to receive contiguously into tmp_buf because displs could make the recvbuf noncontiguous */ MPID_Datatype_get_extent_macro(recvtype, recvtype_extent); MPIR_Type_get_true_extent_impl(recvtype, &recvtype_true_lb, &recvtype_true_extent); total_count = 0; for (i=0; i<comm_size; i++) total_count += recvcounts[i]; if (total_count == 0) goto fn_exit; MPID_Ensure_Aint_fits_in_pointer(total_count*(MPIR_MAX(recvtype_true_extent, recvtype_extent))); MPIR_SCHED_CHKPMEM_MALLOC(tmp_buf, void *, total_count*(MPIR_MAX(recvtype_true_extent,recvtype_extent)), mpi_errno, "tmp_buf"); /* adjust for potential negative lower bound in datatype */ tmp_buf = (void *)((char*)tmp_buf - recvtype_true_lb); /* copy local data into right location in tmp_buf */ position = 0; for (i=0; i<rank; i++) position += recvcounts[i]; if (sendbuf != MPI_IN_PLACE) { mpi_errno = MPID_Sched_copy(sendbuf, sendcount, sendtype, ((char *)tmp_buf + position*recvtype_extent), recvcounts[rank], recvtype, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); } else { /* if in_place specified, local data is found in recvbuf */ mpi_errno = MPID_Sched_copy(((char *)recvbuf + displs[rank]*recvtype_extent), recvcounts[rank], recvtype, ((char *)tmp_buf + position*recvtype_extent), recvcounts[rank], recvtype, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); } curr_count = recvcounts[rank]; /* never used uninitialized w/o this, but compiler can't tell that */ incoming_count = -1; /* [goodell@] random notes that help slightly when deciphering this code: * - mask is also equal to the number of blocks that we are going to recv * (less if comm_size is non-pof2) * - FOO_tree_root is the leftmost (lowest ranked) process with whom FOO has * communicated, directly or indirectly, at the beginning of round the * round. FOO is either "dst" or "my", where "my" means use my rank. * - in each round we are going to recv the blocks * B[dst_tree_root],B[dst_tree_root+1],...,B[min(dst_tree_root+mask,comm_size)] */ mask = 0x1; i = 0; while (mask < comm_size) { dst = rank ^ mask; /* find offset into send and recv buffers. zero out the least significant "i" bits of rank and dst to find root of src and dst subtrees. Use ranks of roots as index to send from and recv into buffer */ dst_tree_root = dst >> i; dst_tree_root <<= i; my_tree_root = rank >> i; my_tree_root <<= i; if (dst < comm_size) { send_offset = 0; for (j = 0; j < my_tree_root; j++) send_offset += recvcounts[j]; recv_offset = 0; for (j = 0; j < dst_tree_root; j++) recv_offset += recvcounts[j]; incoming_count = 0; for (j = dst_tree_root; j < (dst_tree_root + mask) && j < comm_size; ++j) incoming_count += recvcounts[j]; mpi_errno = MPID_Sched_send(((char *)tmp_buf + send_offset * recvtype_extent), curr_count, recvtype, dst, comm_ptr, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); /* sendrecv, no barrier here */ mpi_errno = MPID_Sched_recv(((char *)tmp_buf + recv_offset * recvtype_extent), incoming_count, recvtype, dst, comm_ptr, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); MPID_SCHED_BARRIER(s); curr_count += incoming_count; } /* if some processes in this process's subtree in this step did not have any destination process to communicate with because of non-power-of-two, we need to send them the data that they would normally have received from those processes. That is, the haves in this subtree must send to the havenots. We use a logarithmic recursive-halfing algorithm for this. */ /* This part of the code will not currently be executed because we are not using recursive doubling for non power of two. Mark it as experimental so that it doesn't show up as red in the coverage tests. */ /* --BEGIN EXPERIMENTAL-- */ if (dst_tree_root + mask > comm_size) { int tmp_mask, tree_root; int nprocs_completed = comm_size - my_tree_root - mask; /* nprocs_completed is the number of processes in this subtree that have all the data. Send data to others in a tree fashion. First find root of current tree that is being divided into two. k is the number of least-significant bits in this process's rank that must be zeroed out to find the rank of the root */ /* [goodell@] it looks like (k==i) is always true, could possibly * skip the loop below */ j = mask; k = 0; while (j) { j >>= 1; k++; } k--; tmp_mask = mask >> 1; while (tmp_mask) { dst = rank ^ tmp_mask; tree_root = rank >> k; tree_root <<= k; /* send only if this proc has data and destination doesn't have data. at any step, multiple processes can send if they have the data */ if ((dst > rank) && (rank < tree_root + nprocs_completed) && (dst >= tree_root + nprocs_completed)) { offset = 0; for (j = 0; j < (my_tree_root+mask); j++) offset += recvcounts[j]; offset *= recvtype_extent; /* incoming_count was set in the previous receive. that's the amount of data to be sent now. */ mpi_errno = MPID_Sched_send(((char *)tmp_buf + offset), incoming_count, recvtype, dst, comm_ptr, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); MPID_SCHED_BARRIER(s); } /* recv only if this proc. doesn't have data and sender has data */ else if ((dst < rank) && (dst < tree_root + nprocs_completed) && (rank >= tree_root + nprocs_completed)) { offset = 0; for (j = 0; j < (my_tree_root+mask); j++) offset += recvcounts[j]; /* recalculate incoming_count, since not all processes will have * this value */ incoming_count = 0; for (j = dst_tree_root; j < (dst_tree_root + mask) && j < comm_size; ++j) incoming_count += recvcounts[j]; mpi_errno = MPID_Sched_recv(((char *)tmp_buf + offset * recvtype_extent), incoming_count, recvtype, dst, comm_ptr, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); MPID_SCHED_BARRIER(s); curr_count += incoming_count; } tmp_mask >>= 1; k--; } } /* --END EXPERIMENTAL-- */ mask <<= 1; i++; }
int MPIR_Iexscan(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPID_Comm *comm_ptr, MPID_Sched_t s) { int mpi_errno = MPI_SUCCESS; int rank, comm_size; int mask, dst, is_commutative, flag; MPI_Aint true_extent, true_lb, extent; void *partial_scan, *tmp_buf; MPIR_SCHED_CHKPMEM_DECL(2); if (count == 0) goto fn_exit; comm_size = comm_ptr->local_size; rank = comm_ptr->rank; is_commutative = MPIR_Op_is_commutative(op); /* need to allocate temporary buffer to store partial scan*/ MPIR_Type_get_true_extent_impl(datatype, &true_lb, &true_extent); MPID_Datatype_get_extent_macro(datatype, extent); MPIR_SCHED_CHKPMEM_MALLOC(partial_scan, void *, (count*(MPIR_MAX(true_extent,extent))), mpi_errno, "partial_scan"); /* adjust for potential negative lower bound in datatype */ partial_scan = (void *)((char*)partial_scan - true_lb); /* need to allocate temporary buffer to store incoming data*/ MPIR_SCHED_CHKPMEM_MALLOC(tmp_buf, void *, (count*(MPIR_MAX(true_extent,extent))), mpi_errno, "tmp_buf"); /* adjust for potential negative lower bound in datatype */ tmp_buf = (void *)((char*)tmp_buf - true_lb); mpi_errno = MPID_Sched_copy((sendbuf == MPI_IN_PLACE ? recvbuf : sendbuf), count, datatype, partial_scan, count, datatype, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); flag = 0; mask = 0x1; while (mask < comm_size) { dst = rank ^ mask; if (dst < comm_size) { /* Send partial_scan to dst. Recv into tmp_buf */ mpi_errno = MPID_Sched_send(partial_scan, count, datatype, dst, comm_ptr, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); /* sendrecv, no barrier here */ mpi_errno = MPID_Sched_recv(tmp_buf, count, datatype, dst, comm_ptr, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); MPID_SCHED_BARRIER(s); if (rank > dst) { mpi_errno = MPID_Sched_reduce(tmp_buf, partial_scan, count, datatype, op, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); MPID_SCHED_BARRIER(s); /* On rank 0, recvbuf is not defined. For sendbuf==MPI_IN_PLACE recvbuf must not change (per MPI-2.2). On rank 1, recvbuf is to be set equal to the value in sendbuf on rank 0. On others, recvbuf is the scan of values in the sendbufs on lower ranks. */ if (rank != 0) { if (flag == 0) { /* simply copy data recd from rank 0 into recvbuf */ mpi_errno = MPID_Sched_copy(tmp_buf, count, datatype, recvbuf, count, datatype, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); MPID_SCHED_BARRIER(s); flag = 1; } else { mpi_errno = MPID_Sched_reduce(tmp_buf, recvbuf, count, datatype, op, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); MPID_SCHED_BARRIER(s); } } } else { if (is_commutative) { mpi_errno = MPID_Sched_reduce(tmp_buf, partial_scan, count, datatype, op, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); MPID_SCHED_BARRIER(s); } else { mpi_errno = MPID_Sched_reduce(partial_scan, tmp_buf, count, datatype, op, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); MPID_SCHED_BARRIER(s); mpi_errno = MPID_Sched_copy(tmp_buf, count, datatype, partial_scan, count, datatype, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); MPID_SCHED_BARRIER(s); } } } mask <<= 1; } MPIR_SCHED_CHKPMEM_COMMIT(s); fn_exit: return mpi_errno; fn_fail: MPIR_SCHED_CHKPMEM_REAP(s); goto fn_exit; }
int MPIR_Ireduce_scatter_rec_hlv(const void *sendbuf, void *recvbuf, const int recvcounts[], MPI_Datatype datatype, MPI_Op op, MPID_Comm *comm_ptr, MPID_Sched_t s) { int mpi_errno = MPI_SUCCESS; int rank, comm_size, i; MPI_Aint extent, true_extent, true_lb; int *disps; void *tmp_recvbuf, *tmp_results; int type_size ATTRIBUTE((unused)), total_count, dst; int mask; int *newcnts, *newdisps, rem, newdst, send_idx, recv_idx, last_idx, send_cnt, recv_cnt; int pof2, old_i, newrank; MPIR_SCHED_CHKPMEM_DECL(5); comm_size = comm_ptr->local_size; rank = comm_ptr->rank; MPID_Datatype_get_extent_macro(datatype, extent); MPIR_Type_get_true_extent_impl(datatype, &true_lb, &true_extent); MPIU_Assert(MPIR_Op_is_commutative(op)); MPIR_SCHED_CHKPMEM_MALLOC(disps, int *, comm_size * sizeof(int), mpi_errno, "disps"); total_count = 0; for (i=0; i<comm_size; i++) { disps[i] = total_count; total_count += recvcounts[i]; } if (total_count == 0) { goto fn_exit; } MPID_Datatype_get_size_macro(datatype, type_size); /* allocate temp. buffer to receive incoming data */ MPIR_SCHED_CHKPMEM_MALLOC(tmp_recvbuf, void *, total_count*(MPL_MAX(true_extent,extent)), mpi_errno, "tmp_recvbuf"); /* adjust for potential negative lower bound in datatype */ tmp_recvbuf = (void *)((char*)tmp_recvbuf - true_lb); /* need to allocate another temporary buffer to accumulate results because recvbuf may not be big enough */ MPIR_SCHED_CHKPMEM_MALLOC(tmp_results, void *, total_count*(MPL_MAX(true_extent,extent)), mpi_errno, "tmp_results"); /* adjust for potential negative lower bound in datatype */ tmp_results = (void *)((char*)tmp_results - true_lb); /* copy sendbuf into tmp_results */ if (sendbuf != MPI_IN_PLACE) mpi_errno = MPID_Sched_copy(sendbuf, total_count, datatype, tmp_results, total_count, datatype, s); else mpi_errno = MPID_Sched_copy(recvbuf, total_count, datatype, tmp_results, total_count, datatype, s); if (mpi_errno) MPIR_ERR_POP(mpi_errno); MPID_SCHED_BARRIER(s); pof2 = 1; while (pof2 <= comm_size) pof2 <<= 1; pof2 >>=1; rem = comm_size - pof2; /* In the non-power-of-two case, all even-numbered processes of rank < 2*rem send their data to (rank+1). These even-numbered processes no longer participate in the algorithm until the very end. The remaining processes form a nice power-of-two. */ if (rank < 2*rem) { if (rank % 2 == 0) { /* even */ mpi_errno = MPID_Sched_send(tmp_results, total_count, datatype, rank+1, comm_ptr, s); if (mpi_errno) MPIR_ERR_POP(mpi_errno); MPID_SCHED_BARRIER(s); /* temporarily set the rank to -1 so that this process does not pariticipate in recursive doubling */ newrank = -1; } else { /* odd */ mpi_errno = MPID_Sched_recv(tmp_recvbuf, total_count, datatype, rank-1, comm_ptr, s); if (mpi_errno) MPIR_ERR_POP(mpi_errno); MPID_SCHED_BARRIER(s); /* do the reduction on received data. since the ordering is right, it doesn't matter whether the operation is commutative or not. */ mpi_errno = MPID_Sched_reduce(tmp_recvbuf, tmp_results, total_count, datatype, op, s); if (mpi_errno) MPIR_ERR_POP(mpi_errno); MPID_SCHED_BARRIER(s); /* change the rank */ newrank = rank / 2; } } else /* rank >= 2*rem */ newrank = rank - rem; if (newrank != -1) { /* recalculate the recvcounts and disps arrays because the even-numbered processes who no longer participate will have their result calculated by the process to their right (rank+1). */ MPIR_SCHED_CHKPMEM_MALLOC(newcnts, int *, pof2*sizeof(int), mpi_errno, "newcnts"); MPIR_SCHED_CHKPMEM_MALLOC(newdisps, int *, pof2*sizeof(int), mpi_errno, "newdisps"); for (i = 0; i < pof2; i++) { /* what does i map to in the old ranking? */ old_i = (i < rem) ? i*2 + 1 : i + rem; if (old_i < 2*rem) { /* This process has to also do its left neighbor's work */ newcnts[i] = recvcounts[old_i] + recvcounts[old_i-1]; } else newcnts[i] = recvcounts[old_i]; } newdisps[0] = 0; for (i=1; i<pof2; i++) newdisps[i] = newdisps[i-1] + newcnts[i-1]; mask = pof2 >> 1; send_idx = recv_idx = 0; last_idx = pof2; while (mask > 0) { newdst = newrank ^ mask; /* find real rank of dest */ dst = (newdst < rem) ? newdst*2 + 1 : newdst + rem; send_cnt = recv_cnt = 0; if (newrank < newdst) { send_idx = recv_idx + mask; for (i=send_idx; i<last_idx; i++) send_cnt += newcnts[i]; for (i=recv_idx; i<send_idx; i++) recv_cnt += newcnts[i]; } else { recv_idx = send_idx + mask; for (i=send_idx; i<recv_idx; i++) send_cnt += newcnts[i]; for (i=recv_idx; i<last_idx; i++) recv_cnt += newcnts[i]; } /* Send data from tmp_results. Recv into tmp_recvbuf */ { /* avoid sending and receiving pointless 0-byte messages */ int send_dst = (send_cnt ? dst : MPI_PROC_NULL); int recv_dst = (recv_cnt ? dst : MPI_PROC_NULL); mpi_errno = MPID_Sched_send(((char *)tmp_results + newdisps[send_idx]*extent), send_cnt, datatype, send_dst, comm_ptr, s); if (mpi_errno) MPIR_ERR_POP(mpi_errno); mpi_errno = MPID_Sched_recv(((char *) tmp_recvbuf + newdisps[recv_idx]*extent), recv_cnt, datatype, recv_dst, comm_ptr, s); if (mpi_errno) MPIR_ERR_POP(mpi_errno); MPID_SCHED_BARRIER(s); } /* tmp_recvbuf contains data received in this step. tmp_results contains data accumulated so far */ if (recv_cnt) { mpi_errno = MPID_Sched_reduce(((char *)tmp_recvbuf + newdisps[recv_idx]*extent), ((char *)tmp_results + newdisps[recv_idx]*extent), recv_cnt, datatype, op, s); MPID_SCHED_BARRIER(s); } /* update send_idx for next iteration */ send_idx = recv_idx; last_idx = recv_idx + mask; mask >>= 1; } /* copy this process's result from tmp_results to recvbuf */ if (recvcounts[rank]) { mpi_errno = MPID_Sched_copy(((char *)tmp_results + disps[rank]*extent), recvcounts[rank], datatype, recvbuf, recvcounts[rank], datatype, s); if (mpi_errno) MPIR_ERR_POP(mpi_errno); MPID_SCHED_BARRIER(s); } }
int MPIR_Iscatterv(const void *sendbuf, const int sendcounts[], const int displs[], MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPID_Comm *comm_ptr, MPID_Sched_t s) { int mpi_errno = MPI_SUCCESS; int rank, comm_size; MPI_Aint extent; int i; rank = comm_ptr->rank; /* If I'm the root, then scatter */ if (((comm_ptr->comm_kind == MPID_INTRACOMM) && (root == rank)) || ((comm_ptr->comm_kind == MPID_INTERCOMM) && (root == MPI_ROOT))) { if (comm_ptr->comm_kind == MPID_INTRACOMM) comm_size = comm_ptr->local_size; else comm_size = comm_ptr->remote_size; MPID_Datatype_get_extent_macro(sendtype, extent); /* We need a check to ensure extent will fit in a * pointer. That needs extent * (max count) but we can't get * that without looping over the input data. This is at least * a minimal sanity check. Maybe add a global var since we do * loop over sendcount[] in MPI_Scatterv before calling * this? */ MPIU_Ensure_Aint_fits_in_pointer(MPIU_VOID_PTR_CAST_TO_MPI_AINT sendbuf + extent); for (i = 0; i < comm_size; i++) { if (sendcounts[i]) { if ((comm_ptr->comm_kind == MPID_INTRACOMM) && (i == rank)) { if (recvbuf != MPI_IN_PLACE) { mpi_errno = MPID_Sched_copy(((char *)sendbuf+displs[rank]*extent), sendcounts[rank], sendtype, recvbuf, recvcount, recvtype, s); if (mpi_errno) MPIR_ERR_POP(mpi_errno); } } else { mpi_errno = MPID_Sched_send(((char *)sendbuf+displs[i]*extent), sendcounts[i], sendtype, i, comm_ptr, s); if (mpi_errno) MPIR_ERR_POP(mpi_errno); } } } } else if (root != MPI_PROC_NULL) { /* non-root nodes, and in the intercomm. case, non-root nodes on remote side */ if (recvcount) { mpi_errno = MPID_Sched_recv(recvbuf, recvcount, recvtype, root, comm_ptr, s); if (mpi_errno) MPIR_ERR_POP(mpi_errno); } } fn_exit: return mpi_errno; fn_fail: goto fn_exit; }
int MPIR_Ialltoallv_intra(const void *sendbuf, const int sendcounts[], const int sdispls[], MPI_Datatype sendtype, void *recvbuf, const int recvcounts[], const int rdispls[], MPI_Datatype recvtype, MPID_Comm *comm_ptr, MPID_Sched_t s) { int mpi_errno = MPI_SUCCESS; int comm_size; int i, j; int ii, ss, bblock; MPI_Aint send_extent, recv_extent, sendtype_size, recvtype_size; int dst, rank; MPIR_SCHED_CHKPMEM_DECL(1); MPIU_Assert(comm_ptr->comm_kind == MPID_INTRACOMM); comm_size = comm_ptr->local_size; rank = comm_ptr->rank; /* Get extent and size of recvtype, don't look at sendtype for MPI_IN_PLACE */ MPID_Datatype_get_extent_macro(recvtype, recv_extent); MPID_Datatype_get_size_macro(recvtype, recvtype_size); if (sendbuf == MPI_IN_PLACE) { int max_count; void *tmp_buf = NULL; /* The regular MPI_Alltoallv handles MPI_IN_PLACE using pairwise * sendrecv_replace calls. We don't have a sendrecv_replace, so just * malloc the maximum of the counts array entries and then perform the * pairwise exchanges manually with schedule barriers instead. * * Because of this approach all processes must agree on the global * schedule of "sendrecv_replace" operations to avoid deadlock. * * This keeps with the spirit of the MPI-2.2 standard, which is to * conserve memory when using MPI_IN_PLACE for these routines. * Something like MADRE would probably generate a more optimal * algorithm. */ max_count = 0; for (i = 0; i < comm_size; ++i) { max_count = MPIU_MAX(max_count, recvcounts[i]); } MPIR_SCHED_CHKPMEM_MALLOC(tmp_buf, void *, max_count*recv_extent, mpi_errno, "Ialltoallv tmp_buf"); for (i = 0; i < comm_size; ++i) { /* start inner loop at i to avoid re-exchanging data */ for (j = i; j < comm_size; ++j) { if (rank == i && rank == j) { /* no need to "sendrecv_replace" for ourselves */ } else if (rank == i || rank == j) { if (rank == i) dst = j; else dst = i; mpi_errno = MPID_Sched_send(((char *)recvbuf + rdispls[dst]*recv_extent), recvcounts[dst], recvtype, dst, comm_ptr, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); mpi_errno = MPID_Sched_recv(tmp_buf, recvcounts[dst], recvtype, dst, comm_ptr, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); MPID_SCHED_BARRIER(s); mpi_errno = MPID_Sched_copy(tmp_buf, recvcounts[dst], recvtype, ((char *)recvbuf + rdispls[dst]*recv_extent), recvcounts[dst], recvtype, s); if (mpi_errno) MPIU_ERR_POP(mpi_errno); MPID_SCHED_BARRIER(s); } } } MPID_SCHED_BARRIER(s); }