Actual source code: mpits.c

petsc-3.7.3 2016-07-24
Report Typos and Errors
  1: #include <petscsys.h>        /*I  "petscsys.h"  I*/

  3: PetscLogEvent PETSC_BuildTwoSided,PETSC_BuildTwoSidedF;

  5: const char *const PetscBuildTwoSidedTypes[] = {
  6:   "ALLREDUCE",
  7:   "IBARRIER",
  8:   "REDSCATTER",
  9:   "PetscBuildTwoSidedType",
 10:   "PETSC_BUILDTWOSIDED_",
 11:   0
 12: };

 14: static PetscBuildTwoSidedType _twosided_type = PETSC_BUILDTWOSIDED_NOTSET;

 18: /*@
 19:    PetscCommBuildTwoSidedSetType - set algorithm to use when building two-sided communication

 21:    Logically Collective

 23:    Input Arguments:
 24: +  comm - PETSC_COMM_WORLD
 25: -  twosided - algorithm to use in subsequent calls to PetscCommBuildTwoSided()

 27:    Level: developer

 29:    Note:
 30:    This option is currently global, but could be made per-communicator.

 32: .seealso: PetscCommBuildTwoSided(), PetscCommBuildTwoSidedGetType()
 33: @*/
 34: PetscErrorCode PetscCommBuildTwoSidedSetType(MPI_Comm comm,PetscBuildTwoSidedType twosided)
 35: {
 37: #if defined(PETSC_USE_DEBUG)
 39:     PetscMPIInt ierr;
 40:     PetscMPIInt b1[2],b2[2];
 41:     b1[0] = -(PetscMPIInt)twosided;
 42:     b1[1] = (PetscMPIInt)twosided;
 43:     MPIU_Allreduce(b1,b2,2,MPI_INT,MPI_MAX,comm);
 44:     if (-b2[0] != b2[1]) SETERRQ(comm,PETSC_ERR_ARG_WRONG,"Enum value must be same on all processes");
 45:   }
 46: #endif
 47:   _twosided_type = twosided;
 48:   return(0);
 49: }

 53: /*@
 54:    PetscCommBuildTwoSidedGetType - set algorithm to use when building two-sided communication

 56:    Logically Collective

 58:    Output Arguments:
 59: +  comm - communicator on which to query algorithm
 60: -  twosided - algorithm to use for PetscCommBuildTwoSided()

 62:    Level: developer

 64: .seealso: PetscCommBuildTwoSided(), PetscCommBuildTwoSidedSetType()
 65: @*/
 66: PetscErrorCode PetscCommBuildTwoSidedGetType(MPI_Comm comm,PetscBuildTwoSidedType *twosided)
 67: {

 71:   *twosided = PETSC_BUILDTWOSIDED_NOTSET;
 72:   if (_twosided_type == PETSC_BUILDTWOSIDED_NOTSET) {
 73: #if defined(PETSC_HAVE_MPI_IBARRIER)
 74: #  if defined(PETSC_HAVE_MPICH_CH3_SOCK) && !defined(PETSC_HAVE_MPICH_CH3_SOCK_FIXED_NBC_PROGRESS)
 75:     /* Deadlock in Ibarrier: http://trac.mpich.org/projects/mpich/ticket/1785 */
 76:     _twosided_type = PETSC_BUILDTWOSIDED_ALLREDUCE;
 77: #  else
 78:     _twosided_type = PETSC_BUILDTWOSIDED_IBARRIER;
 79: #  endif
 80: #else
 81:     _twosided_type = PETSC_BUILDTWOSIDED_ALLREDUCE;
 82: #endif
 83:     PetscOptionsGetEnum(NULL,NULL,"-build_twosided",PetscBuildTwoSidedTypes,(PetscEnum*)&_twosided_type,NULL);
 84:   }
 85:   *twosided = _twosided_type;
 86:   return(0);
 87: }

 89: #if defined(PETSC_HAVE_MPI_IBARRIER) || defined(PETSC_HAVE_MPIX_IBARRIER)

 93: 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)
 94: {
 96:   PetscMPIInt    nrecvs,tag,done,i;
 97:   MPI_Aint       lb,unitbytes;
 98:   char           *tdata;
 99:   MPI_Request    *sendreqs,barrier;
100:   PetscSegBuffer segrank,segdata;
101:   PetscBool      barrier_started;

104:   PetscCommDuplicate(comm,&comm,&tag);
105:   MPI_Type_get_extent(dtype,&lb,&unitbytes);
106:   if (lb != 0) SETERRQ1(comm,PETSC_ERR_SUP,"Datatype with nonzero lower bound %ld\n",(long)lb);
107:   tdata = (char*)todata;
108:   PetscMalloc1(nto,&sendreqs);
109:   for (i=0; i<nto; i++) {
110:     MPI_Issend((void*)(tdata+count*unitbytes*i),count,dtype,toranks[i],tag,comm,sendreqs+i);
111:   }
112:   PetscSegBufferCreate(sizeof(PetscMPIInt),4,&segrank);
113:   PetscSegBufferCreate(unitbytes,4*count,&segdata);

115:   nrecvs  = 0;
116:   barrier = MPI_REQUEST_NULL;
117:   /* MPICH-3.2 sometimes does not create a request in some "optimized" cases.  This is arguably a standard violation,
118:    * but we need to work around it. */
119:   barrier_started = PETSC_FALSE;
120:   for (done=0; !done; ) {
121:     PetscMPIInt flag;
122:     MPI_Status  status;
123:     MPI_Iprobe(MPI_ANY_SOURCE,tag,comm,&flag,&status);
124:     if (flag) {                 /* incoming message */
125:       PetscMPIInt *recvrank;
126:       void        *buf;
127:       PetscSegBufferGet(segrank,1,&recvrank);
128:       PetscSegBufferGet(segdata,count,&buf);
129:       *recvrank = status.MPI_SOURCE;
130:       MPI_Recv(buf,count,dtype,status.MPI_SOURCE,tag,comm,MPI_STATUS_IGNORE);
131:       nrecvs++;
132:     }
133:     if (!barrier_started) {
134:       PetscMPIInt sent,nsends;
135:       PetscMPIIntCast(nto,&nsends);
136:       MPI_Testall(nsends,sendreqs,&sent,MPI_STATUSES_IGNORE);
137:       if (sent) {
138: #if defined(PETSC_HAVE_MPI_IBARRIER)
139:         MPI_Ibarrier(comm,&barrier);
140: #elif defined(PETSC_HAVE_MPIX_IBARRIER)
141:         MPIX_Ibarrier(comm,&barrier);
142: #endif
143:         barrier_started = PETSC_TRUE;
144:         PetscFree(sendreqs);
145:       }
146:     } else {
147:       MPI_Test(&barrier,&done,MPI_STATUS_IGNORE);
148:     }
149:   }
150:   *nfrom = nrecvs;
151:   PetscSegBufferExtractAlloc(segrank,fromranks);
152:   PetscSegBufferDestroy(&segrank);
153:   PetscSegBufferExtractAlloc(segdata,fromdata);
154:   PetscSegBufferDestroy(&segdata);
155:   PetscCommDestroy(&comm);
156:   return(0);
157: }
158: #endif

162: static PetscErrorCode PetscCommBuildTwoSided_Allreduce(MPI_Comm comm,PetscMPIInt count,MPI_Datatype dtype,PetscMPIInt nto,const PetscMPIInt *toranks,const void *todata,PetscMPIInt *nfrom,PetscMPIInt **fromranks,void *fromdata)
163: {
165:   PetscMPIInt    size,*iflags,nrecvs,tag,*franks,i;
166:   MPI_Aint       lb,unitbytes;
167:   char           *tdata,*fdata;
168:   MPI_Request    *reqs,*sendreqs;
169:   MPI_Status     *statuses;

172:   MPI_Comm_size(comm,&size);
173:   PetscCalloc1(size,&iflags);
174:   for (i=0; i<nto; i++) iflags[toranks[i]] = 1;
175:   PetscGatherNumberOfMessages(comm,iflags,NULL,&nrecvs);
176:   PetscFree(iflags);

178:   PetscCommDuplicate(comm,&comm,&tag);
179:   MPI_Type_get_extent(dtype,&lb,&unitbytes);
180:   if (lb != 0) SETERRQ1(comm,PETSC_ERR_SUP,"Datatype with nonzero lower bound %ld\n",(long)lb);
181:   PetscMalloc(nrecvs*count*unitbytes,&fdata);
182:   tdata    = (char*)todata;
183:   PetscMalloc2(nto+nrecvs,&reqs,nto+nrecvs,&statuses);
184:   sendreqs = reqs + nrecvs;
185:   for (i=0; i<nrecvs; i++) {
186:     MPI_Irecv((void*)(fdata+count*unitbytes*i),count,dtype,MPI_ANY_SOURCE,tag,comm,reqs+i);
187:   }
188:   for (i=0; i<nto; i++) {
189:     MPI_Isend((void*)(tdata+count*unitbytes*i),count,dtype,toranks[i],tag,comm,sendreqs+i);
190:   }
191:   MPI_Waitall(nto+nrecvs,reqs,statuses);
192:   PetscMalloc1(nrecvs,&franks);
193:   for (i=0; i<nrecvs; i++) franks[i] = statuses[i].MPI_SOURCE;
194:   PetscFree2(reqs,statuses);
195:   PetscCommDestroy(&comm);

197:   *nfrom            = nrecvs;
198:   *fromranks        = franks;
199:   *(void**)fromdata = fdata;
200:   return(0);
201: }

203: #if defined(PETSC_HAVE_MPI_REDUCE_SCATTER_BLOCK)
206: static PetscErrorCode PetscCommBuildTwoSided_RedScatter(MPI_Comm comm,PetscMPIInt count,MPI_Datatype dtype,PetscMPIInt nto,const PetscMPIInt *toranks,const void *todata,PetscMPIInt *nfrom,PetscMPIInt **fromranks,void *fromdata)
207: {
209:   PetscMPIInt    size,*iflags,nrecvs,tag,*franks,i;
210:   MPI_Aint       lb,unitbytes;
211:   char           *tdata,*fdata;
212:   MPI_Request    *reqs,*sendreqs;
213:   MPI_Status     *statuses;

216:   MPI_Comm_size(comm,&size);
217:   PetscMalloc1(size,&iflags);
218:   PetscMemzero(iflags,size*sizeof(*iflags));
219:   for (i=0; i<nto; i++) iflags[toranks[i]] = 1;
220:   MPI_Reduce_scatter_block(iflags,&nrecvs,1,MPI_INT,MPI_SUM,comm);
221:   PetscFree(iflags);

223:   PetscCommDuplicate(comm,&comm,&tag);
224:   MPI_Type_get_extent(dtype,&lb,&unitbytes);
225:   if (lb != 0) SETERRQ1(comm,PETSC_ERR_SUP,"Datatype with nonzero lower bound %ld\n",(long)lb);
226:   PetscMalloc(nrecvs*count*unitbytes,&fdata);
227:   tdata    = (char*)todata;
228:   PetscMalloc2(nto+nrecvs,&reqs,nto+nrecvs,&statuses);
229:   sendreqs = reqs + nrecvs;
230:   for (i=0; i<nrecvs; i++) {
231:     MPI_Irecv((void*)(fdata+count*unitbytes*i),count,dtype,MPI_ANY_SOURCE,tag,comm,reqs+i);
232:   }
233:   for (i=0; i<nto; i++) {
234:     MPI_Isend((void*)(tdata+count*unitbytes*i),count,dtype,toranks[i],tag,comm,sendreqs+i);
235:   }
236:   MPI_Waitall(nto+nrecvs,reqs,statuses);
237:   PetscMalloc1(nrecvs,&franks);
238:   for (i=0; i<nrecvs; i++) franks[i] = statuses[i].MPI_SOURCE;
239:   PetscFree2(reqs,statuses);
240:   PetscCommDestroy(&comm);

242:   *nfrom            = nrecvs;
243:   *fromranks        = franks;
244:   *(void**)fromdata = fdata;
245:   return(0);
246: }
247: #endif

251: /*@C
252:    PetscCommBuildTwoSided - discovers communicating ranks given one-sided information, moving constant-sized data in the process (often message lengths)

254:    Collective on MPI_Comm

256:    Input Arguments:
257: +  comm - communicator
258: .  count - number of entries to send/receive (must match on all ranks)
259: .  dtype - datatype to send/receive from each rank (must match on all ranks)
260: .  nto - number of ranks to send data to
261: .  toranks - ranks to send to (array of length nto)
262: -  todata - data to send to each rank (packed)

264:    Output Arguments:
265: +  nfrom - number of ranks receiving messages from
266: .  fromranks - ranks receiving messages from (length nfrom; caller should PetscFree())
267: -  fromdata - packed data from each rank, each with count entries of type dtype (length nfrom, caller responsible for PetscFree())

269:    Level: developer

271:    Options Database Keys:
272: .  -build_twosided <allreduce|ibarrier|redscatter> - algorithm to set up two-sided communication

274:    Notes:
275:    This memory-scalable interface is an alternative to calling PetscGatherNumberOfMessages() and
276:    PetscGatherMessageLengths(), possibly with a subsequent round of communication to send other constant-size data.

278:    Basic data types as well as contiguous types are supported, but non-contiguous (e.g., strided) types are not.

280:    References:
281: .  1. - Hoefler, Siebert and Lumsdaine, The MPI_Ibarrier implementation uses the algorithm in
282:    Scalable communication protocols for dynamic sparse data exchange, 2010.

284: .seealso: PetscGatherNumberOfMessages(), PetscGatherMessageLengths()
285: @*/
286: PetscErrorCode PetscCommBuildTwoSided(MPI_Comm comm,PetscMPIInt count,MPI_Datatype dtype,PetscMPIInt nto,const PetscMPIInt *toranks,const void *todata,PetscMPIInt *nfrom,PetscMPIInt **fromranks,void *fromdata)
287: {
288:   PetscErrorCode         ierr;
289:   PetscBuildTwoSidedType buildtype = PETSC_BUILDTWOSIDED_NOTSET;

292:   PetscSysInitializePackage();
293:   PetscLogEventBegin(PETSC_BuildTwoSided,0,0,0,0);
294:   PetscCommBuildTwoSidedGetType(comm,&buildtype);
295:   switch (buildtype) {
296:   case PETSC_BUILDTWOSIDED_IBARRIER:
297: #if defined(PETSC_HAVE_MPI_IBARRIER) || defined(PETSC_HAVE_MPIX_IBARRIER)
298:     PetscCommBuildTwoSided_Ibarrier(comm,count,dtype,nto,toranks,todata,nfrom,fromranks,fromdata);
299: #else
300:     SETERRQ(comm,PETSC_ERR_PLIB,"MPI implementation does not provide MPI_Ibarrier (part of MPI-3)");
301: #endif
302:     break;
303:   case PETSC_BUILDTWOSIDED_ALLREDUCE:
304:     PetscCommBuildTwoSided_Allreduce(comm,count,dtype,nto,toranks,todata,nfrom,fromranks,fromdata);
305:     break;
306:   case PETSC_BUILDTWOSIDED_REDSCATTER:
307: #if defined(PETSC_HAVE_MPI_REDUCE_SCATTER_BLOCK)
308:     PetscCommBuildTwoSided_RedScatter(comm,count,dtype,nto,toranks,todata,nfrom,fromranks,fromdata);
309: #else
310:     SETERRQ(comm,PETSC_ERR_PLIB,"MPI implementation does not provide MPI_Reduce_scatter_block (part of MPI-2.2)");
311: #endif
312:     break;
313:   default: SETERRQ(comm,PETSC_ERR_PLIB,"Unknown method for building two-sided communication");
314:   }
315:   PetscLogEventEnd(PETSC_BuildTwoSided,0,0,0,0);
316:   return(0);
317: }

321: static PetscErrorCode PetscCommBuildTwoSidedFReq_Reference(MPI_Comm comm,PetscMPIInt count,MPI_Datatype dtype,PetscMPIInt nto,const PetscMPIInt *toranks,const void *todata,
322:                                                            PetscMPIInt *nfrom,PetscMPIInt **fromranks,void *fromdata,PetscMPIInt ntags,MPI_Request **toreqs,MPI_Request **fromreqs,
323:                                                            PetscErrorCode (*send)(MPI_Comm,const PetscMPIInt[],PetscMPIInt,PetscMPIInt,void*,MPI_Request[],void*),
324:                                                            PetscErrorCode (*recv)(MPI_Comm,const PetscMPIInt[],PetscMPIInt,void*,MPI_Request[],void*),void *ctx)
325: {
327:   PetscMPIInt i,*tag;
328:   MPI_Aint    lb,unitbytes;
329:   MPI_Request *sendreq,*recvreq;

332:   PetscMalloc1(ntags,&tag);
333:   if (ntags > 0) {
334:     PetscCommDuplicate(comm,&comm,&tag[0]);
335:   }
336:   for (i=1; i<ntags; i++) {
337:     PetscCommGetNewTag(comm,&tag[i]);
338:   }

340:   /* Perform complete initial rendezvous */
341:   PetscCommBuildTwoSided(comm,count,dtype,nto,toranks,todata,nfrom,fromranks,fromdata);

343:   PetscMalloc1(nto*ntags,&sendreq);
344:   PetscMalloc1(*nfrom*ntags,&recvreq);

346:   MPI_Type_get_extent(dtype,&lb,&unitbytes);
347:   if (lb != 0) SETERRQ1(comm,PETSC_ERR_SUP,"Datatype with nonzero lower bound %ld\n",(long)lb);
348:   for (i=0; i<nto; i++) {
349:     PetscMPIInt k;
350:     for (k=0; k<ntags; k++) sendreq[i*ntags+k] = MPI_REQUEST_NULL;
351:     (*send)(comm,tag,i,toranks[i],((char*)todata)+count*unitbytes*i,sendreq+i*ntags,ctx);
352:   }
353:   for (i=0; i<*nfrom; i++) {
354:     void *header = (*(char**)fromdata) + count*unitbytes*i;
355:     PetscMPIInt k;
356:     for (k=0; k<ntags; k++) recvreq[i*ntags+k] = MPI_REQUEST_NULL;
357:     (*recv)(comm,tag,(*fromranks)[i],header,recvreq+i*ntags,ctx);
358:   }
359:   PetscFree(tag);
360:   PetscCommDestroy(&comm);
361:   *toreqs = sendreq;
362:   *fromreqs = recvreq;
363:   return(0);
364: }

366: #if defined(PETSC_HAVE_MPI_IBARRIER) || defined(PETSC_HAVE_MPIX_IBARRIER)

370: static PetscErrorCode PetscCommBuildTwoSidedFReq_Ibarrier(MPI_Comm comm,PetscMPIInt count,MPI_Datatype dtype,PetscMPIInt nto,const PetscMPIInt *toranks,const void *todata,
371:                                                           PetscMPIInt *nfrom,PetscMPIInt **fromranks,void *fromdata,PetscMPIInt ntags,MPI_Request **toreqs,MPI_Request **fromreqs,
372:                                                           PetscErrorCode (*send)(MPI_Comm,const PetscMPIInt[],PetscMPIInt,PetscMPIInt,void*,MPI_Request[],void*),
373:                                                           PetscErrorCode (*recv)(MPI_Comm,const PetscMPIInt[],PetscMPIInt,void*,MPI_Request[],void*),void *ctx)
374: {
376:   PetscMPIInt    nrecvs,tag,*tags,done,i;
377:   MPI_Aint       lb,unitbytes;
378:   char           *tdata;
379:   MPI_Request    *sendreqs,*usendreqs,*req,barrier;
380:   PetscSegBuffer segrank,segdata,segreq;
381:   PetscBool      barrier_started;

384:   PetscCommDuplicate(comm,&comm,&tag);
385:   PetscMalloc1(ntags,&tags);
386:   for (i=0; i<ntags; i++) {
387:     PetscCommGetNewTag(comm,&tags[i]);
388:   }
389:   MPI_Type_get_extent(dtype,&lb,&unitbytes);
390:   if (lb != 0) SETERRQ1(comm,PETSC_ERR_SUP,"Datatype with nonzero lower bound %ld\n",(long)lb);
391:   tdata = (char*)todata;
392:   PetscMalloc1(nto,&sendreqs);
393:   PetscMalloc1(nto*ntags,&usendreqs);
394:   /* Post synchronous sends */
395:   for (i=0; i<nto; i++) {
396:     MPI_Issend((void*)(tdata+count*unitbytes*i),count,dtype,toranks[i],tag,comm,sendreqs+i);
397:   }
398:   /* Post actual payloads.  These are typically larger messages.  Hopefully sending these later does not slow down the
399:    * synchronous messages above. */
400:   for (i=0; i<nto; i++) {
401:     PetscMPIInt k;
402:     for (k=0; k<ntags; k++) usendreqs[i*ntags+k] = MPI_REQUEST_NULL;
403:     (*send)(comm,tags,i,toranks[i],tdata+count*unitbytes*i,usendreqs+i*ntags,ctx);
404:   }

406:   PetscSegBufferCreate(sizeof(PetscMPIInt),4,&segrank);
407:   PetscSegBufferCreate(unitbytes,4*count,&segdata);
408:   PetscSegBufferCreate(sizeof(MPI_Request),4,&segreq);

410:   nrecvs  = 0;
411:   barrier = MPI_REQUEST_NULL;
412:   /* MPICH-3.2 sometimes does not create a request in some "optimized" cases.  This is arguably a standard violation,
413:    * but we need to work around it. */
414:   barrier_started = PETSC_FALSE;
415:   for (done=0; !done; ) {
416:     PetscMPIInt flag;
417:     MPI_Status  status;
418:     MPI_Iprobe(MPI_ANY_SOURCE,tag,comm,&flag,&status);
419:     if (flag) {                 /* incoming message */
420:       PetscMPIInt *recvrank,k;
421:       void        *buf;
422:       PetscSegBufferGet(segrank,1,&recvrank);
423:       PetscSegBufferGet(segdata,count,&buf);
424:       *recvrank = status.MPI_SOURCE;
425:       MPI_Recv(buf,count,dtype,status.MPI_SOURCE,tag,comm,MPI_STATUS_IGNORE);
426:       PetscSegBufferGet(segreq,ntags,&req);
427:       for (k=0; k<ntags; k++) req[k] = MPI_REQUEST_NULL;
428:       (*recv)(comm,tags,status.MPI_SOURCE,buf,req,ctx);
429:       nrecvs++;
430:     }
431:     if (!barrier_started) {
432:       PetscMPIInt sent,nsends;
433:       PetscMPIIntCast(nto,&nsends);
434:       MPI_Testall(nsends,sendreqs,&sent,MPI_STATUSES_IGNORE);
435:       if (sent) {
436: #if defined(PETSC_HAVE_MPI_IBARRIER)
437:         MPI_Ibarrier(comm,&barrier);
438: #elif defined(PETSC_HAVE_MPIX_IBARRIER)
439:         MPIX_Ibarrier(comm,&barrier);
440: #endif
441:         barrier_started = PETSC_TRUE;
442:       }
443:     } else {
444:       MPI_Test(&barrier,&done,MPI_STATUS_IGNORE);
445:     }
446:   }
447:   *nfrom = nrecvs;
448:   PetscSegBufferExtractAlloc(segrank,fromranks);
449:   PetscSegBufferDestroy(&segrank);
450:   PetscSegBufferExtractAlloc(segdata,fromdata);
451:   PetscSegBufferDestroy(&segdata);
452:   *toreqs = usendreqs;
453:   PetscSegBufferExtractAlloc(segreq,fromreqs);
454:   PetscSegBufferDestroy(&segreq);
455:   PetscFree(sendreqs);
456:   PetscFree(tags);
457:   PetscCommDestroy(&comm);
458:   return(0);
459: }
460: #endif

464: /*@C
465:    PetscCommBuildTwoSidedF - discovers communicating ranks given one-sided information, calling user-defined functions during rendezvous

467:    Collective on MPI_Comm

469:    Input Arguments:
470: +  comm - communicator
471: .  count - number of entries to send/receive in initial rendezvous (must match on all ranks)
472: .  dtype - datatype to send/receive from each rank (must match on all ranks)
473: .  nto - number of ranks to send data to
474: .  toranks - ranks to send to (array of length nto)
475: .  todata - data to send to each rank (packed)
476: .  ntags - number of tags needed by send/recv callbacks
477: .  send - callback invoked on sending process when ready to send primary payload
478: .  recv - callback invoked on receiving process after delivery of rendezvous message
479: -  ctx - context for callbacks

481:    Output Arguments:
482: +  nfrom - number of ranks receiving messages from
483: .  fromranks - ranks receiving messages from (length nfrom; caller should PetscFree())
484: -  fromdata - packed data from each rank, each with count entries of type dtype (length nfrom, caller responsible for PetscFree())

486:    Level: developer

488:    Notes:
489:    This memory-scalable interface is an alternative to calling PetscGatherNumberOfMessages() and
490:    PetscGatherMessageLengths(), possibly with a subsequent round of communication to send other data.

492:    Basic data types as well as contiguous types are supported, but non-contiguous (e.g., strided) types are not.

494:    References:
495: .  1. - Hoefler, Siebert and Lumsdaine, The MPI_Ibarrier implementation uses the algorithm in
496:    Scalable communication protocols for dynamic sparse data exchange, 2010.

498: .seealso: PetscCommBuildTwoSided(), PetscCommBuildTwoSidedFReq(), PetscGatherNumberOfMessages(), PetscGatherMessageLengths()
499: @*/
500: PetscErrorCode PetscCommBuildTwoSidedF(MPI_Comm comm,PetscMPIInt count,MPI_Datatype dtype,PetscMPIInt nto,const PetscMPIInt *toranks,const void *todata,PetscMPIInt *nfrom,PetscMPIInt **fromranks,void *fromdata,PetscMPIInt ntags,
501:                                        PetscErrorCode (*send)(MPI_Comm,const PetscMPIInt[],PetscMPIInt,PetscMPIInt,void*,MPI_Request[],void*),
502:                                        PetscErrorCode (*recv)(MPI_Comm,const PetscMPIInt[],PetscMPIInt,void*,MPI_Request[],void*),void *ctx)
503: {
505:   MPI_Request    *toreqs,*fromreqs;

508:   PetscCommBuildTwoSidedFReq(comm,count,dtype,nto,toranks,todata,nfrom,fromranks,fromdata,ntags,&toreqs,&fromreqs,send,recv,ctx);
509:   MPI_Waitall(nto*ntags,toreqs,MPI_STATUSES_IGNORE);
510:   MPI_Waitall(*nfrom*ntags,fromreqs,MPI_STATUSES_IGNORE);
511:   PetscFree(toreqs);
512:   PetscFree(fromreqs);
513:   return(0);
514: }

518: /*@C
519:    PetscCommBuildTwoSidedFReq - discovers communicating ranks given one-sided information, calling user-defined functions during rendezvous, returns requests

521:    Collective on MPI_Comm

523:    Input Arguments:
524: +  comm - communicator
525: .  count - number of entries to send/receive in initial rendezvous (must match on all ranks)
526: .  dtype - datatype to send/receive from each rank (must match on all ranks)
527: .  nto - number of ranks to send data to
528: .  toranks - ranks to send to (array of length nto)
529: .  todata - data to send to each rank (packed)
530: .  ntags - number of tags needed by send/recv callbacks
531: .  send - callback invoked on sending process when ready to send primary payload
532: .  recv - callback invoked on receiving process after delivery of rendezvous message
533: -  ctx - context for callbacks

535:    Output Arguments:
536: +  nfrom - number of ranks receiving messages from
537: .  fromranks - ranks receiving messages from (length nfrom; caller should PetscFree())
538: .  fromdata - packed data from each rank, each with count entries of type dtype (length nfrom, caller responsible for PetscFree())
539: .  toreqs - array of nto*ntags sender requests (caller must wait on these, then PetscFree())
540: -  fromreqs - array of nfrom*ntags receiver requests (caller must wait on these, then PetscFree())

542:    Level: developer

544:    Notes:
545:    This memory-scalable interface is an alternative to calling PetscGatherNumberOfMessages() and
546:    PetscGatherMessageLengths(), possibly with a subsequent round of communication to send other data.

548:    Basic data types as well as contiguous types are supported, but non-contiguous (e.g., strided) types are not.

550:    References:
551: .  1. - Hoefler, Siebert and Lumsdaine, The MPI_Ibarrier implementation uses the algorithm in
552:    Scalable communication protocols for dynamic sparse data exchange, 2010.

554: .seealso: PetscCommBuildTwoSided(), PetscCommBuildTwoSidedF(), PetscGatherNumberOfMessages(), PetscGatherMessageLengths()
555: @*/
556: PetscErrorCode PetscCommBuildTwoSidedFReq(MPI_Comm comm,PetscMPIInt count,MPI_Datatype dtype,PetscMPIInt nto,const PetscMPIInt *toranks,const void *todata,
557:                                           PetscMPIInt *nfrom,PetscMPIInt **fromranks,void *fromdata,PetscMPIInt ntags,MPI_Request **toreqs,MPI_Request **fromreqs,
558:                                           PetscErrorCode (*send)(MPI_Comm,const PetscMPIInt[],PetscMPIInt,PetscMPIInt,void*,MPI_Request[],void*),
559:                                           PetscErrorCode (*recv)(MPI_Comm,const PetscMPIInt[],PetscMPIInt,void*,MPI_Request[],void*),void *ctx)
560: {
561:   PetscErrorCode         ierr,(*f)(MPI_Comm,PetscMPIInt,MPI_Datatype,PetscMPIInt,const PetscMPIInt[],const void*,
562:                                    PetscMPIInt*,PetscMPIInt**,void*,PetscMPIInt,MPI_Request**,MPI_Request**,
563:                                    PetscErrorCode (*send)(MPI_Comm,const PetscMPIInt[],PetscMPIInt,PetscMPIInt,void*,MPI_Request[],void*),
564:                                    PetscErrorCode (*recv)(MPI_Comm,const PetscMPIInt[],PetscMPIInt,void*,MPI_Request[],void*),void *ctx);
565:   PetscBuildTwoSidedType buildtype = PETSC_BUILDTWOSIDED_NOTSET;
566:   PetscMPIInt i,size;

569:   PetscSysInitializePackage();
570:   MPI_Comm_size(comm,&size);
571:   for (i=0; i<nto; i++) {
572:     if (toranks[i] < 0 || size <= toranks[i]) SETERRQ3(comm,PETSC_ERR_ARG_OUTOFRANGE,"toranks[%d] %d not in comm size %d",i,toranks[i],size);
573:   }
574:   PetscLogEventBegin(PETSC_BuildTwoSidedF,0,0,0,0);
575:   PetscCommBuildTwoSidedGetType(comm,&buildtype);
576:   switch (buildtype) {
577:   case PETSC_BUILDTWOSIDED_IBARRIER:
578: #if defined(PETSC_HAVE_MPI_IBARRIER) || defined(PETSC_HAVE_MPIX_IBARRIER)
579:     f = PetscCommBuildTwoSidedFReq_Ibarrier;
580: #else
581:     SETERRQ(comm,PETSC_ERR_PLIB,"MPI implementation does not provide MPI_Ibarrier (part of MPI-3)");
582: #endif
583:     break;
584:   case PETSC_BUILDTWOSIDED_ALLREDUCE:
585:   case PETSC_BUILDTWOSIDED_REDSCATTER:
586:     f = PetscCommBuildTwoSidedFReq_Reference;
587:     break;
588:   default: SETERRQ(comm,PETSC_ERR_PLIB,"Unknown method for building two-sided communication");
589:   }
590:   (*f)(comm,count,dtype,nto,toranks,todata,nfrom,fromranks,fromdata,ntags,toreqs,fromreqs,send,recv,ctx);
591:   PetscLogEventEnd(PETSC_BuildTwoSidedF,0,0,0,0);
592:   return(0);
593: }