|
Packit Service |
c5cf8c |
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
|
|
Packit Service |
c5cf8c |
/*
|
|
Packit Service |
c5cf8c |
*
|
|
Packit Service |
c5cf8c |
* (C) 2001 by Argonne National Laboratory.
|
|
Packit Service |
c5cf8c |
* See COPYRIGHT in top-level directory.
|
|
Packit Service |
c5cf8c |
*/
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
#include "mpiimpl.h"
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/*
|
|
Packit Service |
c5cf8c |
* Ring Algorithm:
|
|
Packit Service |
c5cf8c |
*
|
|
Packit Service |
c5cf8c |
* In the first step, each process i sends its contribution to process
|
|
Packit Service |
c5cf8c |
* i+1 and receives the contribution from process i-1 (with
|
|
Packit Service |
c5cf8c |
* wrap-around). From the second step onwards, each process i
|
|
Packit Service |
c5cf8c |
* forwards to process i+1 the data it received from process i-1 in
|
|
Packit Service |
c5cf8c |
* the previous step. This takes a total of p-1 steps.
|
|
Packit Service |
c5cf8c |
*
|
|
Packit Service |
c5cf8c |
* Cost = (p-1).alpha + n.((p-1)/p).beta
|
|
Packit Service |
c5cf8c |
*
|
|
Packit Service |
c5cf8c |
* This algorithm is preferred to recursive doubling for long messages
|
|
Packit Service |
c5cf8c |
* because we find that this communication pattern (nearest neighbor)
|
|
Packit Service |
c5cf8c |
* performs twice as fast as recursive doubling for long messages (on
|
|
Packit Service |
c5cf8c |
* Myrinet and IBM SP).
|
|
Packit Service |
c5cf8c |
*/
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
#undef FUNCNAME
|
|
Packit Service |
c5cf8c |
#define FUNCNAME MPIR_Allgatherv_intra_ring
|
|
Packit Service |
c5cf8c |
#undef FCNAME
|
|
Packit Service |
c5cf8c |
#define FCNAME MPL_QUOTE(FUNCNAME)
|
|
Packit Service |
c5cf8c |
int MPIR_Allgatherv_intra_ring(const void *sendbuf,
|
|
Packit Service |
c5cf8c |
int sendcount,
|
|
Packit Service |
c5cf8c |
MPI_Datatype sendtype,
|
|
Packit Service |
c5cf8c |
void *recvbuf,
|
|
Packit Service |
c5cf8c |
const int *recvcounts,
|
|
Packit Service |
c5cf8c |
const int *displs,
|
|
Packit Service |
c5cf8c |
MPI_Datatype recvtype,
|
|
Packit Service |
c5cf8c |
MPIR_Comm * comm_ptr, MPIR_Errflag_t * errflag)
|
|
Packit Service |
c5cf8c |
{
|
|
Packit Service |
c5cf8c |
int comm_size, rank, i, left, right;
|
|
Packit Service |
c5cf8c |
int mpi_errno = MPI_SUCCESS;
|
|
Packit Service |
c5cf8c |
int mpi_errno_ret = MPI_SUCCESS;
|
|
Packit Service |
c5cf8c |
MPI_Status status;
|
|
Packit Service |
c5cf8c |
MPI_Aint recvtype_extent;
|
|
Packit Service |
c5cf8c |
int total_count;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
comm_size = comm_ptr->local_size;
|
|
Packit Service |
c5cf8c |
rank = comm_ptr->rank;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
total_count = 0;
|
|
Packit Service |
c5cf8c |
for (i = 0; i < comm_size; i++)
|
|
Packit Service |
c5cf8c |
total_count += recvcounts[i];
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
if (total_count == 0)
|
|
Packit Service |
c5cf8c |
goto fn_exit;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
MPIR_Datatype_get_extent_macro(recvtype, recvtype_extent);
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
char *sbuf = NULL, *rbuf = NULL;
|
|
Packit Service |
c5cf8c |
int soffset, roffset;
|
|
Packit Service |
c5cf8c |
int torecv, tosend, min;
|
|
Packit Service |
c5cf8c |
int sendnow, recvnow;
|
|
Packit Service |
c5cf8c |
int sidx, ridx;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
if (sendbuf != MPI_IN_PLACE) {
|
|
Packit Service |
c5cf8c |
/* First, load the "local" version in the recvbuf. */
|
|
Packit Service |
c5cf8c |
mpi_errno = MPIR_Localcopy(sendbuf, sendcount, sendtype,
|
|
Packit Service |
c5cf8c |
((char *) recvbuf + displs[rank] * recvtype_extent),
|
|
Packit Service |
c5cf8c |
recvcounts[rank], recvtype);
|
|
Packit Service |
c5cf8c |
if (mpi_errno)
|
|
Packit Service |
c5cf8c |
MPIR_ERR_POP(mpi_errno);
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
left = (comm_size + rank - 1) % comm_size;
|
|
Packit Service |
c5cf8c |
right = (rank + 1) % comm_size;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
torecv = total_count - recvcounts[rank];
|
|
Packit Service |
c5cf8c |
tosend = total_count - recvcounts[right];
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
min = recvcounts[0];
|
|
Packit Service |
c5cf8c |
for (i = 1; i < comm_size; i++)
|
|
Packit Service |
c5cf8c |
if (min > recvcounts[i])
|
|
Packit Service |
c5cf8c |
min = recvcounts[i];
|
|
Packit Service |
c5cf8c |
if (min * recvtype_extent < MPIR_CVAR_ALLGATHERV_PIPELINE_MSG_SIZE)
|
|
Packit Service |
c5cf8c |
min = MPIR_CVAR_ALLGATHERV_PIPELINE_MSG_SIZE / recvtype_extent;
|
|
Packit Service |
c5cf8c |
/* Handle the case where the datatype extent is larger than
|
|
Packit Service |
c5cf8c |
* the pipeline size. */
|
|
Packit Service |
c5cf8c |
if (!min)
|
|
Packit Service |
c5cf8c |
min = 1;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
sidx = rank;
|
|
Packit Service |
c5cf8c |
ridx = left;
|
|
Packit Service |
c5cf8c |
soffset = 0;
|
|
Packit Service |
c5cf8c |
roffset = 0;
|
|
Packit Service |
c5cf8c |
while (tosend || torecv) { /* While we have data to send or receive */
|
|
Packit Service |
c5cf8c |
sendnow = ((recvcounts[sidx] - soffset) > min) ? min : (recvcounts[sidx] - soffset);
|
|
Packit Service |
c5cf8c |
recvnow = ((recvcounts[ridx] - roffset) > min) ? min : (recvcounts[ridx] - roffset);
|
|
Packit Service |
c5cf8c |
sbuf = (char *) recvbuf + ((displs[sidx] + soffset) * recvtype_extent);
|
|
Packit Service |
c5cf8c |
rbuf = (char *) recvbuf + ((displs[ridx] + roffset) * recvtype_extent);
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* Protect against wrap-around of indices */
|
|
Packit Service |
c5cf8c |
if (!tosend)
|
|
Packit Service |
c5cf8c |
sendnow = 0;
|
|
Packit Service |
c5cf8c |
if (!torecv)
|
|
Packit Service |
c5cf8c |
recvnow = 0;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* Communicate */
|
|
Packit Service |
c5cf8c |
if (!sendnow && !recvnow) {
|
|
Packit Service |
c5cf8c |
/* Don't do anything. This case is possible if two
|
|
Packit Service |
c5cf8c |
* consecutive processes contribute 0 bytes each. */
|
|
Packit Service |
c5cf8c |
} else if (!sendnow) { /* If there's no data to send, just do a recv call */
|
|
Packit Service |
c5cf8c |
mpi_errno =
|
|
Packit Service |
c5cf8c |
MPIC_Recv(rbuf, recvnow, recvtype, left, MPIR_ALLGATHERV_TAG, comm_ptr, &status,
|
|
Packit Service |
c5cf8c |
errflag);
|
|
Packit Service |
c5cf8c |
if (mpi_errno) {
|
|
Packit Service |
c5cf8c |
/* for communication errors, just record the error but continue */
|
|
Packit Service |
c5cf8c |
*errflag =
|
|
Packit Service |
c5cf8c |
MPIX_ERR_PROC_FAILED ==
|
|
Packit Service |
c5cf8c |
MPIR_ERR_GET_CLASS(mpi_errno) ? MPIR_ERR_PROC_FAILED : MPIR_ERR_OTHER;
|
|
Packit Service |
c5cf8c |
MPIR_ERR_SET(mpi_errno, *errflag, "**fail");
|
|
Packit Service |
c5cf8c |
MPIR_ERR_ADD(mpi_errno_ret, mpi_errno);
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
torecv -= recvnow;
|
|
Packit Service |
c5cf8c |
} else if (!recvnow) { /* If there's no data to receive, just do a send call */
|
|
Packit Service |
c5cf8c |
mpi_errno =
|
|
Packit Service |
c5cf8c |
MPIC_Send(sbuf, sendnow, recvtype, right, MPIR_ALLGATHERV_TAG, comm_ptr, errflag);
|
|
Packit Service |
c5cf8c |
if (mpi_errno) {
|
|
Packit Service |
c5cf8c |
/* for communication errors, just record the error but continue */
|
|
Packit Service |
c5cf8c |
*errflag =
|
|
Packit Service |
c5cf8c |
MPIX_ERR_PROC_FAILED ==
|
|
Packit Service |
c5cf8c |
MPIR_ERR_GET_CLASS(mpi_errno) ? MPIR_ERR_PROC_FAILED : MPIR_ERR_OTHER;
|
|
Packit Service |
c5cf8c |
MPIR_ERR_SET(mpi_errno, *errflag, "**fail");
|
|
Packit Service |
c5cf8c |
MPIR_ERR_ADD(mpi_errno_ret, mpi_errno);
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
tosend -= sendnow;
|
|
Packit Service |
c5cf8c |
} else { /* There's data to be sent and received */
|
|
Packit Service |
c5cf8c |
mpi_errno = MPIC_Sendrecv(sbuf, sendnow, recvtype, right, MPIR_ALLGATHERV_TAG,
|
|
Packit Service |
c5cf8c |
rbuf, recvnow, recvtype, left, MPIR_ALLGATHERV_TAG,
|
|
Packit Service |
c5cf8c |
comm_ptr, &status, errflag);
|
|
Packit Service |
c5cf8c |
if (mpi_errno) {
|
|
Packit Service |
c5cf8c |
/* for communication errors, just record the error but continue */
|
|
Packit Service |
c5cf8c |
*errflag =
|
|
Packit Service |
c5cf8c |
MPIX_ERR_PROC_FAILED ==
|
|
Packit Service |
c5cf8c |
MPIR_ERR_GET_CLASS(mpi_errno) ? MPIR_ERR_PROC_FAILED : MPIR_ERR_OTHER;
|
|
Packit Service |
c5cf8c |
MPIR_ERR_SET(mpi_errno, *errflag, "**fail");
|
|
Packit Service |
c5cf8c |
MPIR_ERR_ADD(mpi_errno_ret, mpi_errno);
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
tosend -= sendnow;
|
|
Packit Service |
c5cf8c |
torecv -= recvnow;
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
soffset += sendnow;
|
|
Packit Service |
c5cf8c |
roffset += recvnow;
|
|
Packit Service |
c5cf8c |
if (soffset == recvcounts[sidx]) {
|
|
Packit Service |
c5cf8c |
soffset = 0;
|
|
Packit Service |
c5cf8c |
sidx = (sidx + comm_size - 1) % comm_size;
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
if (roffset == recvcounts[ridx]) {
|
|
Packit Service |
c5cf8c |
roffset = 0;
|
|
Packit Service |
c5cf8c |
ridx = (ridx + comm_size - 1) % comm_size;
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
fn_exit:
|
|
Packit Service |
c5cf8c |
if (mpi_errno_ret)
|
|
Packit Service |
c5cf8c |
mpi_errno = mpi_errno_ret;
|
|
Packit Service |
c5cf8c |
else if (*errflag != MPIR_ERR_NONE)
|
|
Packit Service |
c5cf8c |
MPIR_ERR_SET(mpi_errno, *errflag, "**coll_fail");
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
return mpi_errno;
|
|
Packit Service |
c5cf8c |
fn_fail:
|
|
Packit Service |
c5cf8c |
goto fn_exit;
|
|
Packit Service |
c5cf8c |
}
|