#include /*I "petscsys.h" I*/ #include PetscLogEvent PETSC_BuildTwoSided; PetscLogEvent PETSC_BuildTwoSidedF; const char *const PetscBuildTwoSidedTypes[] = { "ALLREDUCE", "IBARRIER", "REDSCATTER", "PetscBuildTwoSidedType", "PETSC_BUILDTWOSIDED_", NULL }; static PetscBuildTwoSidedType _twosided_type = PETSC_BUILDTWOSIDED_NOTSET; /*@ PetscCommBuildTwoSidedSetType - set algorithm to use when building two-sided communication Logically Collective Input Parameters: + comm - PETSC_COMM_WORLD - twosided - algorithm to use in subsequent calls to PetscCommBuildTwoSided() Level: developer Note: This option is currently global, but could be made per-communicator. .seealso: `PetscCommBuildTwoSided()`, `PetscCommBuildTwoSidedGetType()` @*/ PetscErrorCode PetscCommBuildTwoSidedSetType(MPI_Comm comm,PetscBuildTwoSidedType twosided) { PetscFunctionBegin; if (PetscDefined(USE_DEBUG)) { /* We don't have a PetscObject so can't use PetscValidLogicalCollectiveEnum */ PetscMPIInt b1[2],b2[2]; b1[0] = -(PetscMPIInt)twosided; b1[1] = (PetscMPIInt)twosided; PetscCall(MPIU_Allreduce(b1,b2,2,MPI_INT,MPI_MAX,comm)); PetscCheck(-b2[0] == b2[1],comm,PETSC_ERR_ARG_WRONG,"Enum value must be same on all processes"); } _twosided_type = twosided; PetscFunctionReturn(0); } /*@ PetscCommBuildTwoSidedGetType - set algorithm to use when building two-sided communication Logically Collective Output Parameters: + comm - communicator on which to query algorithm - twosided - algorithm to use for PetscCommBuildTwoSided() Level: developer .seealso: `PetscCommBuildTwoSided()`, `PetscCommBuildTwoSidedSetType()` @*/ PetscErrorCode PetscCommBuildTwoSidedGetType(MPI_Comm comm,PetscBuildTwoSidedType *twosided) { PetscMPIInt size; PetscFunctionBegin; *twosided = PETSC_BUILDTWOSIDED_NOTSET; if (_twosided_type == PETSC_BUILDTWOSIDED_NOTSET) { PetscCallMPI(MPI_Comm_size(comm,&size)); _twosided_type = PETSC_BUILDTWOSIDED_ALLREDUCE; /* default for small comms, see https://gitlab.com/petsc/petsc/-/merge_requests/2611 */ #if defined(PETSC_HAVE_MPI_NONBLOCKING_COLLECTIVES) if (size > 1024) _twosided_type = PETSC_BUILDTWOSIDED_IBARRIER; #endif PetscCall(PetscOptionsGetEnum(NULL,NULL,"-build_twosided",PetscBuildTwoSidedTypes,(PetscEnum*)&_twosided_type,NULL)); } *twosided = _twosided_type; PetscFunctionReturn(0); } #if defined(PETSC_HAVE_MPI_NONBLOCKING_COLLECTIVES) static PetscErrorCode PetscCommBuildTwoSided_Ibarrier(MPI_Comm comm,PetscMPIInt count,MPI_Datatype dtype,PetscMPIInt nto,const PetscMPIInt *toranks,const void *todata,PetscMPIInt *nfrom,PetscMPIInt **fromranks,void *fromdata) { PetscMPIInt nrecvs,tag,done,i; MPI_Aint lb,unitbytes; char *tdata; MPI_Request *sendreqs,barrier; PetscSegBuffer segrank,segdata; PetscBool barrier_started; PetscFunctionBegin; PetscCall(PetscCommDuplicate(comm,&comm,&tag)); PetscCallMPI(MPI_Type_get_extent(dtype,&lb,&unitbytes)); PetscCheck(lb == 0,comm,PETSC_ERR_SUP,"Datatype with nonzero lower bound %ld",(long)lb); tdata = (char*)todata; PetscCall(PetscMalloc1(nto,&sendreqs)); for (i=0; iiflags) { PetscCall(PetscCalloc1(size,&counter->iflags)); iflags = counter->iflags; } else { iflags = counter->iflags; PetscCall(PetscArrayzero(iflags,size)); } for (i=0; iiflags) { PetscCall(PetscCalloc1(size,&counter->iflags)); iflags = counter->iflags; } else { iflags = counter->iflags; PetscCall(PetscArrayzero(iflags,size)); } for (i=0; i - algorithm to set up two-sided communication. Default is allreduce for communicators with <= 1024 ranks, otherwise ibarrier. Notes: This memory-scalable interface is an alternative to calling PetscGatherNumberOfMessages() and PetscGatherMessageLengths(), possibly with a subsequent round of communication to send other constant-size data. Basic data types as well as contiguous types are supported, but non-contiguous (e.g., strided) types are not. References: . * - Hoefler, Siebert and Lumsdaine, The MPI_Ibarrier implementation uses the algorithm in Scalable communication protocols for dynamic sparse data exchange, 2010. .seealso: `PetscGatherNumberOfMessages()`, `PetscGatherMessageLengths()` @*/ PetscErrorCode PetscCommBuildTwoSided(MPI_Comm comm,PetscMPIInt count,MPI_Datatype dtype,PetscMPIInt nto,const PetscMPIInt *toranks,const void *todata,PetscMPIInt *nfrom,PetscMPIInt **fromranks,void *fromdata) { PetscBuildTwoSidedType buildtype = PETSC_BUILDTWOSIDED_NOTSET; PetscFunctionBegin; PetscCall(PetscSysInitializePackage()); PetscCall(PetscLogEventSync(PETSC_BuildTwoSided,comm)); PetscCall(PetscLogEventBegin(PETSC_BuildTwoSided,0,0,0,0)); PetscCall(PetscCommBuildTwoSidedGetType(comm,&buildtype)); switch (buildtype) { case PETSC_BUILDTWOSIDED_IBARRIER: #if defined(PETSC_HAVE_MPI_NONBLOCKING_COLLECTIVES) PetscCall(PetscCommBuildTwoSided_Ibarrier(comm,count,dtype,nto,toranks,todata,nfrom,fromranks,fromdata)); break; #else SETERRQ(comm,PETSC_ERR_PLIB,"MPI implementation does not provide MPI_Ibarrier (part of MPI-3)"); #endif case PETSC_BUILDTWOSIDED_ALLREDUCE: PetscCall(PetscCommBuildTwoSided_Allreduce(comm,count,dtype,nto,toranks,todata,nfrom,fromranks,fromdata)); break; case PETSC_BUILDTWOSIDED_REDSCATTER: #if defined(PETSC_HAVE_MPI_REDUCE_SCATTER_BLOCK) PetscCall(PetscCommBuildTwoSided_RedScatter(comm,count,dtype,nto,toranks,todata,nfrom,fromranks,fromdata)); break; #else SETERRQ(comm,PETSC_ERR_PLIB,"MPI implementation does not provide MPI_Reduce_scatter_block (part of MPI-2.2)"); #endif default: SETERRQ(comm,PETSC_ERR_PLIB,"Unknown method for building two-sided communication"); } PetscCall(PetscLogEventEnd(PETSC_BuildTwoSided,0,0,0,0)); PetscFunctionReturn(0); } static PetscErrorCode PetscCommBuildTwoSidedFReq_Reference(MPI_Comm comm,PetscMPIInt count,MPI_Datatype dtype,PetscMPIInt nto,const PetscMPIInt *toranks,const void *todata, PetscMPIInt *nfrom,PetscMPIInt **fromranks,void *fromdata,PetscMPIInt ntags,MPI_Request **toreqs,MPI_Request **fromreqs, PetscErrorCode (*send)(MPI_Comm,const PetscMPIInt[],PetscMPIInt,PetscMPIInt,void*,MPI_Request[],void*), PetscErrorCode (*recv)(MPI_Comm,const PetscMPIInt[],PetscMPIInt,void*,MPI_Request[],void*),void *ctx) { PetscMPIInt i,*tag; MPI_Aint lb,unitbytes; MPI_Request *sendreq,*recvreq; PetscFunctionBegin; PetscCall(PetscMalloc1(ntags,&tag)); if (ntags > 0) { PetscCall(PetscCommDuplicate(comm,&comm,&tag[0])); } for (i=1; i= 0 && size > toranks[i],comm,PETSC_ERR_ARG_OUTOFRANGE,"toranks[%d] %d not in comm size %d",i,toranks[i],size); } PetscCall(PetscLogEventSync(PETSC_BuildTwoSidedF,comm)); PetscCall(PetscLogEventBegin(PETSC_BuildTwoSidedF,0,0,0,0)); PetscCall(PetscCommBuildTwoSidedGetType(comm,&buildtype)); switch (buildtype) { case PETSC_BUILDTWOSIDED_IBARRIER: #if defined(PETSC_HAVE_MPI_NONBLOCKING_COLLECTIVES) f = PetscCommBuildTwoSidedFReq_Ibarrier; break; #else SETERRQ(comm,PETSC_ERR_PLIB,"MPI implementation does not provide MPI_Ibarrier (part of MPI-3)"); #endif case PETSC_BUILDTWOSIDED_ALLREDUCE: case PETSC_BUILDTWOSIDED_REDSCATTER: f = PetscCommBuildTwoSidedFReq_Reference; break; default: SETERRQ(comm,PETSC_ERR_PLIB,"Unknown method for building two-sided communication"); } PetscCall((*f)(comm,count,dtype,nto,toranks,todata,nfrom,fromranks,fromdata,ntags,toreqs,fromreqs,send,recv,ctx)); PetscCall(PetscLogEventEnd(PETSC_BuildTwoSidedF,0,0,0,0)); PetscFunctionReturn(0); }