xref: /petsc/src/sys/utils/mpimesg.c (revision d083f849a86f1f43e18d534ee43954e2786cb29a)
1e5c89e4eSSatish Balay 
2c6db04a5SJed Brown #include <petscsys.h>        /*I  "petscsys.h"  I*/
3e5c89e4eSSatish Balay 
4e5c89e4eSSatish Balay 
5e5c89e4eSSatish Balay /*@C
6e5c89e4eSSatish Balay   PetscGatherNumberOfMessages -  Computes the number of messages a node expects to receive
7e5c89e4eSSatish Balay 
8*d083f849SBarry Smith   Collective
9e5c89e4eSSatish Balay 
10e5c89e4eSSatish Balay   Input Parameters:
11e5c89e4eSSatish Balay + comm     - Communicator
12e5c89e4eSSatish Balay . iflags   - an array of integers of length sizeof(comm). A '1' in ilengths[i] represent a
130298fd71SBarry Smith              message from current node to ith node. Optionally NULL
14e5c89e4eSSatish Balay - ilengths - Non zero ilengths[i] represent a message to i of length ilengths[i].
150298fd71SBarry Smith              Optionally NULL.
16e5c89e4eSSatish Balay 
17e5c89e4eSSatish Balay   Output Parameters:
18e5c89e4eSSatish Balay . nrecvs    - number of messages received
19e5c89e4eSSatish Balay 
20e5c89e4eSSatish Balay   Level: developer
21e5c89e4eSSatish Balay 
22e5c89e4eSSatish Balay   Notes:
23e5c89e4eSSatish Balay   With this info, the correct message lengths can be determined using
24e5c89e4eSSatish Balay   PetscGatherMessageLengths()
25e5c89e4eSSatish Balay 
26e5c89e4eSSatish Balay   Either iflags or ilengths should be provided.  If iflags is not
270298fd71SBarry Smith   provided (NULL) it can be computed from ilengths. If iflags is
28e5c89e4eSSatish Balay   provided, ilengths is not required.
29e5c89e4eSSatish Balay 
30e5c89e4eSSatish Balay .seealso: PetscGatherMessageLengths()
31e5c89e4eSSatish Balay @*/
327087cfbeSBarry Smith PetscErrorCode  PetscGatherNumberOfMessages(MPI_Comm comm,const PetscMPIInt iflags[],const PetscMPIInt ilengths[],PetscMPIInt *nrecvs)
33e5c89e4eSSatish Balay {
340298fd71SBarry Smith   PetscMPIInt    size,rank,*recv_buf,i,*iflags_local = NULL,*iflags_localm = NULL;
35e5c89e4eSSatish Balay   PetscErrorCode ierr;
36e5c89e4eSSatish Balay 
37e5c89e4eSSatish Balay   PetscFunctionBegin;
38e5c89e4eSSatish Balay   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
39e5c89e4eSSatish Balay   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
40e5c89e4eSSatish Balay 
41dcca6d9dSJed Brown   ierr = PetscMalloc2(size,&recv_buf,size,&iflags_localm);CHKERRQ(ierr);
42e5c89e4eSSatish Balay 
43e5c89e4eSSatish Balay   /* If iflags not provided, compute iflags from ilengths */
44e5c89e4eSSatish Balay   if (!iflags) {
45e32f2f54SBarry Smith     if (!ilengths) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Either iflags or ilengths should be provided");
46e5c89e4eSSatish Balay     iflags_local = iflags_localm;
47e5c89e4eSSatish Balay     for (i=0; i<size; i++) {
48e5c89e4eSSatish Balay       if (ilengths[i]) iflags_local[i] = 1;
49e5c89e4eSSatish Balay       else iflags_local[i] = 0;
50e5c89e4eSSatish Balay     }
51a297a907SKarl Rupp   } else iflags_local = (PetscMPIInt*) iflags;
52e5c89e4eSSatish Balay 
53e5c89e4eSSatish Balay   /* Post an allreduce to determine the numer of messages the current node will receive */
54b2566f29SBarry Smith   ierr    = MPIU_Allreduce(iflags_local,recv_buf,size,MPI_INT,MPI_SUM,comm);CHKERRQ(ierr);
55e5c89e4eSSatish Balay   *nrecvs = recv_buf[rank];
56e5c89e4eSSatish Balay 
57e5c89e4eSSatish Balay   ierr = PetscFree2(recv_buf,iflags_localm);CHKERRQ(ierr);
58e5c89e4eSSatish Balay   PetscFunctionReturn(0);
59e5c89e4eSSatish Balay }
60e5c89e4eSSatish Balay 
61e5c89e4eSSatish Balay 
62e5c89e4eSSatish Balay /*@C
63e5c89e4eSSatish Balay   PetscGatherMessageLengths - Computes info about messages that a MPI-node will receive,
64e5c89e4eSSatish Balay   including (from-id,length) pairs for each message.
65e5c89e4eSSatish Balay 
66*d083f849SBarry Smith   Collective
67e5c89e4eSSatish Balay 
68e5c89e4eSSatish Balay   Input Parameters:
69e5c89e4eSSatish Balay + comm      - Communicator
70e5c89e4eSSatish Balay . nsends    - number of messages that are to be sent.
71e5c89e4eSSatish Balay . nrecvs    - number of messages being received
72e5c89e4eSSatish Balay - ilengths  - an array of integers of length sizeof(comm)
73e5c89e4eSSatish Balay               a non zero ilengths[i] represent a message to i of length ilengths[i]
74e5c89e4eSSatish Balay 
75e5c89e4eSSatish Balay 
76e5c89e4eSSatish Balay   Output Parameters:
77e5c89e4eSSatish Balay + onodes    - list of node-ids from which messages are expected
78e5c89e4eSSatish Balay - olengths  - corresponding message lengths
79e5c89e4eSSatish Balay 
80e5c89e4eSSatish Balay   Level: developer
81e5c89e4eSSatish Balay 
82e5c89e4eSSatish Balay   Notes:
83e5c89e4eSSatish Balay   With this info, the correct MPI_Irecv() can be posted with the correct
84e5c89e4eSSatish Balay   from-id, with a buffer with the right amount of memory required.
85e5c89e4eSSatish Balay 
86e5c89e4eSSatish Balay   The calling function deallocates the memory in onodes and olengths
87e5c89e4eSSatish Balay 
88e5c89e4eSSatish Balay   To determine nrecevs, one can use PetscGatherNumberOfMessages()
89e5c89e4eSSatish Balay 
90e5c89e4eSSatish Balay .seealso: PetscGatherNumberOfMessages()
91e5c89e4eSSatish Balay @*/
927087cfbeSBarry Smith PetscErrorCode  PetscGatherMessageLengths(MPI_Comm comm,PetscMPIInt nsends,PetscMPIInt nrecvs,const PetscMPIInt ilengths[],PetscMPIInt **onodes,PetscMPIInt **olengths)
93e5c89e4eSSatish Balay {
94e5c89e4eSSatish Balay   PetscErrorCode ierr;
95e5c89e4eSSatish Balay   PetscMPIInt    size,tag,i,j;
960298fd71SBarry Smith   MPI_Request    *s_waits  = NULL,*r_waits = NULL;
970298fd71SBarry Smith   MPI_Status     *w_status = NULL;
98e5c89e4eSSatish Balay 
99e5c89e4eSSatish Balay   PetscFunctionBegin;
100e5c89e4eSSatish Balay   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
101e5c89e4eSSatish Balay   ierr = PetscCommGetNewTag(comm,&tag);CHKERRQ(ierr);
102e5c89e4eSSatish Balay 
103e5c89e4eSSatish Balay   /* cannot use PetscMalloc3() here because in the call to MPI_Waitall() they MUST be contiguous */
104dcca6d9dSJed Brown   ierr    = PetscMalloc2(nrecvs+nsends,&r_waits,nrecvs+nsends,&w_status);CHKERRQ(ierr);
105e5c89e4eSSatish Balay   s_waits = r_waits+nrecvs;
106e5c89e4eSSatish Balay 
107e5c89e4eSSatish Balay   /* Post the Irecv to get the message length-info */
108785e854fSJed Brown   ierr = PetscMalloc1(nrecvs,olengths);CHKERRQ(ierr);
109e5c89e4eSSatish Balay   for (i=0; i<nrecvs; i++) {
110e5c89e4eSSatish Balay     ierr = MPI_Irecv((*olengths)+i,1,MPI_INT,MPI_ANY_SOURCE,tag,comm,r_waits+i);CHKERRQ(ierr);
111e5c89e4eSSatish Balay   }
112e5c89e4eSSatish Balay 
113e5c89e4eSSatish Balay   /* Post the Isends with the message length-info */
114e5c89e4eSSatish Balay   for (i=0,j=0; i<size; ++i) {
115e5c89e4eSSatish Balay     if (ilengths[i]) {
116300a7f5bSBarry Smith       ierr = MPI_Isend((void*)(ilengths+i),1,MPI_INT,i,tag,comm,s_waits+j);CHKERRQ(ierr);
117e5c89e4eSSatish Balay       j++;
118e5c89e4eSSatish Balay     }
119e5c89e4eSSatish Balay   }
120e5c89e4eSSatish Balay 
121e5c89e4eSSatish Balay   /* Post waits on sends and receivs */
122e5c89e4eSSatish Balay   if (nrecvs+nsends) {ierr = MPI_Waitall(nrecvs+nsends,r_waits,w_status);CHKERRQ(ierr);}
123e5c89e4eSSatish Balay 
124e5c89e4eSSatish Balay   /* Pack up the received data */
125785e854fSJed Brown   ierr = PetscMalloc1(nrecvs,onodes);CHKERRQ(ierr);
126a297a907SKarl Rupp   for (i=0; i<nrecvs; ++i) (*onodes)[i] = w_status[i].MPI_SOURCE;
127e5c89e4eSSatish Balay   ierr = PetscFree2(r_waits,w_status);CHKERRQ(ierr);
128e5c89e4eSSatish Balay   PetscFunctionReturn(0);
129e5c89e4eSSatish Balay }
130dd6ea824SBarry Smith 
131e5c89e4eSSatish Balay /*@C
132e5c89e4eSSatish Balay   PetscGatherMessageLengths2 - Computes info about messages that a MPI-node will receive,
133e5c89e4eSSatish Balay   including (from-id,length) pairs for each message. Same functionality as PetscGatherMessageLengths()
134e5c89e4eSSatish Balay   except it takes TWO ilenths and output TWO olengths.
135e5c89e4eSSatish Balay 
136*d083f849SBarry Smith   Collective
137e5c89e4eSSatish Balay 
138e5c89e4eSSatish Balay   Input Parameters:
139e5c89e4eSSatish Balay + comm      - Communicator
140e5c89e4eSSatish Balay . nsends    - number of messages that are to be sent.
141e5c89e4eSSatish Balay . nrecvs    - number of messages being received
142e5c89e4eSSatish Balay - ilengths1, ilengths2 - array of integers of length sizeof(comm)
143e5c89e4eSSatish Balay               a non zero ilengths[i] represent a message to i of length ilengths[i]
144e5c89e4eSSatish Balay 
145e5c89e4eSSatish Balay   Output Parameters:
146e5c89e4eSSatish Balay + onodes    - list of node-ids from which messages are expected
147e5c89e4eSSatish Balay - olengths1, olengths2 - corresponding message lengths
148e5c89e4eSSatish Balay 
149e5c89e4eSSatish Balay   Level: developer
150e5c89e4eSSatish Balay 
151e5c89e4eSSatish Balay   Notes:
152e5c89e4eSSatish Balay   With this info, the correct MPI_Irecv() can be posted with the correct
153e5c89e4eSSatish Balay   from-id, with a buffer with the right amount of memory required.
154e5c89e4eSSatish Balay 
155e5c89e4eSSatish Balay   The calling function deallocates the memory in onodes and olengths
156e5c89e4eSSatish Balay 
157e5c89e4eSSatish Balay   To determine nrecevs, one can use PetscGatherNumberOfMessages()
158e5c89e4eSSatish Balay 
159e5c89e4eSSatish Balay .seealso: PetscGatherMessageLengths() and PetscGatherNumberOfMessages()
160e5c89e4eSSatish Balay @*/
1617087cfbeSBarry Smith PetscErrorCode  PetscGatherMessageLengths2(MPI_Comm comm,PetscMPIInt nsends,PetscMPIInt nrecvs,const PetscMPIInt ilengths1[],const PetscMPIInt ilengths2[],PetscMPIInt **onodes,PetscMPIInt **olengths1,PetscMPIInt **olengths2)
162e5c89e4eSSatish Balay {
163e5c89e4eSSatish Balay   PetscErrorCode ierr;
1640298fd71SBarry Smith   PetscMPIInt    size,tag,i,j,*buf_s = NULL,*buf_r = NULL,*buf_j = NULL;
1650298fd71SBarry Smith   MPI_Request    *s_waits  = NULL,*r_waits = NULL;
1660298fd71SBarry Smith   MPI_Status     *w_status = NULL;
167e5c89e4eSSatish Balay 
168e5c89e4eSSatish Balay   PetscFunctionBegin;
169e5c89e4eSSatish Balay   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
170e5c89e4eSSatish Balay   ierr = PetscCommGetNewTag(comm,&tag);CHKERRQ(ierr);
171e5c89e4eSSatish Balay 
1723bf92927SBarry Smith   /* cannot use PetscMalloc5() because r_waits and s_waits must be contiguous for the call to MPI_Waitall() */
173dcca6d9dSJed Brown   ierr = PetscMalloc4(nrecvs+nsends,&r_waits,2*nrecvs,&buf_r,2*nsends,&buf_s,nrecvs+nsends,&w_status);CHKERRQ(ierr);
174e5c89e4eSSatish Balay   s_waits = r_waits + nrecvs;
175e5c89e4eSSatish Balay 
176e5c89e4eSSatish Balay   /* Post the Irecv to get the message length-info */
177854ce69bSBarry Smith   ierr = PetscMalloc1(nrecvs+1,olengths1);CHKERRQ(ierr);
178854ce69bSBarry Smith   ierr = PetscMalloc1(nrecvs+1,olengths2);CHKERRQ(ierr);
179e5c89e4eSSatish Balay   for (i=0; i<nrecvs; i++) {
180e5c89e4eSSatish Balay     buf_j = buf_r + (2*i);
181e5c89e4eSSatish Balay     ierr  = MPI_Irecv(buf_j,2,MPI_INT,MPI_ANY_SOURCE,tag,comm,r_waits+i);CHKERRQ(ierr);
182e5c89e4eSSatish Balay   }
183e5c89e4eSSatish Balay 
184e5c89e4eSSatish Balay   /* Post the Isends with the message length-info */
185e5c89e4eSSatish Balay   for (i=0,j=0; i<size; ++i) {
186e5c89e4eSSatish Balay     if (ilengths1[i]) {
187e5c89e4eSSatish Balay       buf_j    = buf_s + (2*j);
188e5c89e4eSSatish Balay       buf_j[0] = *(ilengths1+i);
189e5c89e4eSSatish Balay       buf_j[1] = *(ilengths2+i);
190e5c89e4eSSatish Balay       ierr = MPI_Isend(buf_j,2,MPI_INT,i,tag,comm,s_waits+j);CHKERRQ(ierr);
191e5c89e4eSSatish Balay       j++;
192e5c89e4eSSatish Balay     }
193e5c89e4eSSatish Balay   }
194f327f304SBarry Smith   if (j != nsends) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"j %d not equal to expected number of sends %d\n",j,nsends);
195e5c89e4eSSatish Balay 
196e5c89e4eSSatish Balay   /* Post waits on sends and receivs */
197e5c89e4eSSatish Balay   if (nrecvs+nsends) {ierr = MPI_Waitall(nrecvs+nsends,r_waits,w_status);CHKERRQ(ierr);}
198e5c89e4eSSatish Balay 
199e5c89e4eSSatish Balay 
200e5c89e4eSSatish Balay   /* Pack up the received data */
201854ce69bSBarry Smith   ierr = PetscMalloc1(nrecvs+1,onodes);CHKERRQ(ierr);
202e5c89e4eSSatish Balay   for (i=0; i<nrecvs; ++i) {
203e5c89e4eSSatish Balay     (*onodes)[i]    = w_status[i].MPI_SOURCE;
204e5c89e4eSSatish Balay     buf_j           = buf_r + (2*i);
205e5c89e4eSSatish Balay     (*olengths1)[i] = buf_j[0];
206e5c89e4eSSatish Balay     (*olengths2)[i] = buf_j[1];
207e5c89e4eSSatish Balay   }
208e5c89e4eSSatish Balay 
209e5c89e4eSSatish Balay   ierr = PetscFree4(r_waits,buf_r,buf_s,w_status);CHKERRQ(ierr);
210e5c89e4eSSatish Balay   PetscFunctionReturn(0);
211e5c89e4eSSatish Balay }
212e5c89e4eSSatish Balay 
213e5c89e4eSSatish Balay /*
214e5c89e4eSSatish Balay 
215e5c89e4eSSatish Balay   Allocate a bufffer sufficient to hold messages of size specified in olengths.
216e5c89e4eSSatish Balay   And post Irecvs on these buffers using node info from onodes
217e5c89e4eSSatish Balay 
218e5c89e4eSSatish Balay  */
2197087cfbeSBarry Smith PetscErrorCode  PetscPostIrecvInt(MPI_Comm comm,PetscMPIInt tag,PetscMPIInt nrecvs,const PetscMPIInt onodes[],const PetscMPIInt olengths[],PetscInt ***rbuf,MPI_Request **r_waits)
220e5c89e4eSSatish Balay {
221e5c89e4eSSatish Balay   PetscErrorCode ierr;
222c05d87d6SBarry Smith   PetscInt       **rbuf_t,i,len = 0;
223e5c89e4eSSatish Balay   MPI_Request    *r_waits_t;
224e5c89e4eSSatish Balay 
225e5c89e4eSSatish Balay   PetscFunctionBegin;
226e5c89e4eSSatish Balay   /* compute memory required for recv buffers */
227e5c89e4eSSatish Balay   for (i=0; i<nrecvs; i++) len += olengths[i];  /* each message length */
228e5c89e4eSSatish Balay 
229e5c89e4eSSatish Balay   /* allocate memory for recv buffers */
230854ce69bSBarry Smith   ierr = PetscMalloc1(nrecvs+1,&rbuf_t);CHKERRQ(ierr);
231785e854fSJed Brown   ierr = PetscMalloc1(len,&rbuf_t[0]);CHKERRQ(ierr);
232e5c89e4eSSatish Balay   for (i=1; i<nrecvs; ++i) rbuf_t[i] = rbuf_t[i-1] + olengths[i-1];
233e5c89e4eSSatish Balay 
234e5c89e4eSSatish Balay   /* Post the receives */
235785e854fSJed Brown   ierr = PetscMalloc1(nrecvs,&r_waits_t);CHKERRQ(ierr);
236e5c89e4eSSatish Balay   for (i=0; i<nrecvs; ++i) {
237e5c89e4eSSatish Balay     ierr = MPI_Irecv(rbuf_t[i],olengths[i],MPIU_INT,onodes[i],tag,comm,r_waits_t+i);CHKERRQ(ierr);
238e5c89e4eSSatish Balay   }
239e5c89e4eSSatish Balay 
240e5c89e4eSSatish Balay   *rbuf    = rbuf_t;
241e5c89e4eSSatish Balay   *r_waits = r_waits_t;
242e5c89e4eSSatish Balay   PetscFunctionReturn(0);
243e5c89e4eSSatish Balay }
244e5c89e4eSSatish Balay 
2457087cfbeSBarry Smith PetscErrorCode  PetscPostIrecvScalar(MPI_Comm comm,PetscMPIInt tag,PetscMPIInt nrecvs,const PetscMPIInt onodes[],const PetscMPIInt olengths[],PetscScalar ***rbuf,MPI_Request **r_waits)
246e5c89e4eSSatish Balay {
247e5c89e4eSSatish Balay   PetscErrorCode ierr;
248052f0c41SBarry Smith   PetscMPIInt    i;
249e5c89e4eSSatish Balay   PetscScalar    **rbuf_t;
250e5c89e4eSSatish Balay   MPI_Request    *r_waits_t;
251c05d87d6SBarry Smith   PetscInt       len = 0;
252e5c89e4eSSatish Balay 
253fe28d99cSBarry Smith   PetscFunctionBegin;
254e5c89e4eSSatish Balay   /* compute memory required for recv buffers */
255e5c89e4eSSatish Balay   for (i=0; i<nrecvs; i++) len += olengths[i];  /* each message length */
256e5c89e4eSSatish Balay 
257e5c89e4eSSatish Balay   /* allocate memory for recv buffers */
258854ce69bSBarry Smith   ierr = PetscMalloc1(nrecvs+1,&rbuf_t);CHKERRQ(ierr);
259785e854fSJed Brown   ierr = PetscMalloc1(len,&rbuf_t[0]);CHKERRQ(ierr);
260e5c89e4eSSatish Balay   for (i=1; i<nrecvs; ++i) rbuf_t[i] = rbuf_t[i-1] + olengths[i-1];
261e5c89e4eSSatish Balay 
262e5c89e4eSSatish Balay   /* Post the receives */
263785e854fSJed Brown   ierr = PetscMalloc1(nrecvs,&r_waits_t);CHKERRQ(ierr);
264e5c89e4eSSatish Balay   for (i=0; i<nrecvs; ++i) {
265e5c89e4eSSatish Balay     ierr = MPI_Irecv(rbuf_t[i],olengths[i],MPIU_SCALAR,onodes[i],tag,comm,r_waits_t+i);CHKERRQ(ierr);
266e5c89e4eSSatish Balay   }
267e5c89e4eSSatish Balay 
268e5c89e4eSSatish Balay   *rbuf    = rbuf_t;
269e5c89e4eSSatish Balay   *r_waits = r_waits_t;
270e5c89e4eSSatish Balay   PetscFunctionReturn(0);
271e5c89e4eSSatish Balay }
272