xref: /petsc/src/sys/objects/tagm.c (revision 655f41cf3b9a6ce1666930e971e6cb96050f61df)
1 #define PETSC_DLL
2 /*
3       Some PETSc utilites
4 */
5 #include "petscsys.h"             /*I    "petscsys.h"   I*/
6 #if defined(PETSC_HAVE_STDLIB_H)
7 #include <stdlib.h>
8 #endif
9 
10 /* ---------------------------------------------------------------- */
11 /*
12    A simple way to manage tags inside a communicator.
13 
14    It uses the attributes to determine if a new communicator
15       is needed and to store the available tags.
16 
17    Notes on the implementation
18 
19    The tagvalues to use are stored in a two element array.  The first element
20    is the first free tag value.  The second is used to indicate how
21    many "copies" of the communicator there are used in destroying.
22 
23 
24 */
25 
26 static PetscMPIInt Petsc_Tag_keyval       = MPI_KEYVAL_INVALID;
27 static PetscMPIInt Petsc_InnerComm_keyval = MPI_KEYVAL_INVALID;
28 static PetscMPIInt Petsc_OuterComm_keyval = MPI_KEYVAL_INVALID;
29 EXTERN_C_BEGIN
30 #undef __FUNCT__
31 #define __FUNCT__ "Petsc_DelTag"
32 /*
33    Private routine to delete internal storage when a communicator is freed.
34   This is called by MPI, not by users.
35 
36     Note: this is declared extern "C" because it is passed to MPI_Keyval_create
37 
38 */
39 PetscMPIInt PETSC_DLLEXPORT Petsc_DelTag(MPI_Comm comm,PetscMPIInt keyval,void* attr_val,void* extra_state)
40 {
41   PetscErrorCode ierr;
42 
43   PetscFunctionBegin;
44   ierr = PetscInfo1(0,"Deleting tag data in an MPI_Comm %ld\n",(long)comm);if (ierr) PetscFunctionReturn((PetscMPIInt)ierr);
45   ierr = PetscFree(attr_val);if (ierr) PetscFunctionReturn((PetscMPIInt)ierr);
46   PetscFunctionReturn(MPI_SUCCESS);
47 }
48 EXTERN_C_END
49 
50 EXTERN_C_BEGIN
51 #undef __FUNCT__
52 #define __FUNCT__ "Petsc_DelComm"
53 /*
54    Private routine to delete internal storage when a communicator is freed.
55   This is called by MPI, not by users.
56 
57     Note: this is declared extern "C" because it is passed to MPI_Keyval_create
58 
59 */
60 PetscMPIInt PETSC_DLLEXPORT Petsc_DelComm(MPI_Comm comm,PetscMPIInt keyval,void* attr_val,void* extra_state)
61 {
62   PetscErrorCode ierr;
63 
64   PetscFunctionBegin;
65   ierr = PetscInfo1(0,"Deleting PETSc communicator imbedded in a user MPI_Comm %ld\n",(long)comm);if (ierr) PetscFunctionReturn((PetscMPIInt)ierr);
66   /* actually don't delete anything because we cannot increase the reference count of the communicator anyways */
67   PetscFunctionReturn(MPI_SUCCESS);
68 }
69 EXTERN_C_END
70 
71 #undef __FUNCT__
72 #define __FUNCT__ "PetscObjectGetNewTag"
73 /*@C
74     PetscObjectGetNewTag - Gets a unique new tag from a PETSc object. All
75     processors that share the object MUST call this routine EXACTLY the same
76     number of times.  This tag should only be used with the current objects
77     communicator; do NOT use it with any other MPI communicator.
78 
79     Collective on PetscObject
80 
81     Input Parameter:
82 .   obj - the PETSc object; this must be cast with a (PetscObject), for example,
83          PetscObjectGetNewTag((PetscObject)mat,&tag);
84 
85     Output Parameter:
86 .   tag - the new tag
87 
88     Level: developer
89 
90     Concepts: tag^getting
91     Concepts: message tag^getting
92     Concepts: MPI message tag^getting
93 
94 .seealso: PetscCommGetNewTag()
95 @*/
96 PetscErrorCode PETSC_DLLEXPORT PetscObjectGetNewTag(PetscObject obj,PetscMPIInt *tag)
97 {
98   PetscErrorCode ierr;
99 
100   PetscFunctionBegin;
101   ierr = PetscCommGetNewTag(obj->comm,tag);CHKERRQ(ierr);
102   PetscFunctionReturn(0);
103 }
104 
105 #undef __FUNCT__
106 #define __FUNCT__ "PetscCommGetNewTag"
107 /*@
108     PetscCommGetNewTag - Gets a unique new tag from a PETSc communicator. All
109     processors that share the communicator MUST call this routine EXACTLY the same
110     number of times.  This tag should only be used with the current objects
111     communicator; do NOT use it with any other MPI communicator.
112 
113     Collective on comm
114 
115     Input Parameter:
116 .   comm - the MPI communicator
117 
118     Output Parameter:
119 .   tag - the new tag
120 
121     Level: developer
122 
123     Concepts: tag^getting
124     Concepts: message tag^getting
125     Concepts: MPI message tag^getting
126 
127 .seealso: PetscObjectGetNewTag(), PetscCommDuplicate()
128 @*/
129 PetscErrorCode PETSC_DLLEXPORT PetscCommGetNewTag(MPI_Comm comm,PetscMPIInt *tag)
130 {
131   PetscErrorCode ierr;
132   PetscMPIInt    *tagvalp=0,*maxval;
133   PetscTruth     flg;
134 
135   PetscFunctionBegin;
136   PetscValidIntPointer(tag,2);
137 
138   if (Petsc_Tag_keyval == MPI_KEYVAL_INVALID) {
139     ierr = MPI_Keyval_create(MPI_NULL_COPY_FN,Petsc_DelTag,&Petsc_Tag_keyval,(void*)0);CHKERRQ(ierr);
140     ierr = MPI_Keyval_create(MPI_NULL_COPY_FN,Petsc_DelComm,&Petsc_InnerComm_keyval,(void*)0);CHKERRQ(ierr);
141     ierr = MPI_Keyval_create(MPI_NULL_COPY_FN,Petsc_DelComm,&Petsc_OuterComm_keyval,(void*)0);CHKERRQ(ierr);
142   }
143 
144   ierr = MPI_Attr_get(comm,Petsc_Tag_keyval,(void**)&tagvalp,(PetscMPIInt*)&flg);CHKERRQ(ierr);
145   if (!flg) SETERRQ(PETSC_ERR_ARG_CORRUPT,"Bad MPI communicator supplied; must be a PETSc communicator");
146 
147   if (tagvalp[0] < 1) {
148     ierr = PetscInfo1(0,"Out of tags for object, starting to recycle. Comm reference count %d\n",tagvalp[1]);CHKERRQ(ierr);
149     ierr       = MPI_Attr_get(MPI_COMM_WORLD,MPI_TAG_UB,(void**)&maxval,(PetscMPIInt*)&flg);CHKERRQ(ierr);
150     if (!flg) {
151       SETERRQ(PETSC_ERR_LIB,"MPI error: MPI_Attr_get() is not returning a MPI_TAG_UB");
152     }
153     tagvalp[0] = *maxval - 128; /* hope that any still active tags were issued right at the beginning of the run */
154   }
155 
156   *tag = tagvalp[0]--;
157 #if defined(PETSC_USE_DEBUG)
158   /*
159      Hanging here means that some processes have called PetscCommDuplicate() and others have not.
160      This likley means that a subset of processes in a MPI_Comm have attempted to create a PetscObject!
161      ALL processes that share a communicator MUST shared objects created from that communicator.
162   */
163   ierr = MPI_Barrier(comm);CHKERRQ(ierr);
164 #endif
165   PetscFunctionReturn(0);
166 }
167 
168 #undef __FUNCT__
169 #define __FUNCT__ "PetscCommDuplicate"
170 /*@C
171   PetscCommDuplicate - Duplicates the communicator only if it is not already a PETSc
172                          communicator.
173 
174   Collective on MPI_Comm
175 
176   Input Parameters:
177 . comm_in - Input communicator
178 
179   Output Parameters:
180 + comm_out - Output communicator.  May be comm_in.
181 - first_tag - Tag available that has not already been used with this communicator (you may
182               pass in PETSC_NULL if you do not need a tag)
183 
184   PETSc communicators are just regular MPI communicators that keep track of which
185   tags have been used to prevent tag conflict. If you pass a non-PETSc communicator into
186   a PETSc creation routine it will attach a private communicator for use in the objects communications.
187 
188   Level: developer
189 
190   Concepts: communicator^duplicate
191 
192 .seealso: PetscObjectGetNewTag(), PetscCommGetNewTag()
193 @*/
194 PetscErrorCode PETSC_DLLEXPORT PetscCommDuplicate(MPI_Comm comm_in,MPI_Comm *comm_out,PetscMPIInt* first_tag)
195 {
196   PetscErrorCode ierr;
197   PetscMPIInt    *tagvalp,*maxval;
198   PetscTruth     flg;
199 
200   PetscFunctionBegin;
201   if (Petsc_Tag_keyval == MPI_KEYVAL_INVALID) {
202     ierr = MPI_Keyval_create(MPI_NULL_COPY_FN,Petsc_DelTag,&Petsc_Tag_keyval,(void*)0);CHKERRQ(ierr);
203     ierr = MPI_Keyval_create(MPI_NULL_COPY_FN,Petsc_DelComm,&Petsc_InnerComm_keyval,(void*)0);CHKERRQ(ierr);
204     ierr = MPI_Keyval_create(MPI_NULL_COPY_FN,Petsc_DelComm,&Petsc_OuterComm_keyval,(void*)0);CHKERRQ(ierr);
205   }
206   ierr = MPI_Attr_get(comm_in,Petsc_Tag_keyval,(void**)&tagvalp,(PetscMPIInt*)&flg);CHKERRQ(ierr);
207 
208   if (!flg) {
209     void *ptr;
210     /* check if this communicator has a PETSc communicator imbedded in it */
211     ierr = MPI_Attr_get(comm_in,Petsc_InnerComm_keyval,&ptr,(PetscMPIInt*)&flg);CHKERRQ(ierr);
212     if (!flg) {
213       /* This communicator is not yet known to this system, so we duplicate it and set its value */
214       ierr       = MPI_Comm_dup(comm_in,comm_out);CHKERRQ(ierr);
215       ierr       = MPI_Attr_get(MPI_COMM_WORLD,MPI_TAG_UB,(void**)&maxval,(PetscMPIInt*)&flg);CHKERRQ(ierr);
216       if (!flg) {
217         SETERRQ(PETSC_ERR_LIB,"MPI error: MPI_Attr_get() is not returning a MPI_TAG_UB");
218       }
219       ierr = PetscMalloc(2*sizeof(PetscMPIInt),&tagvalp);CHKERRQ(ierr);
220       tagvalp[0] = *maxval;
221       tagvalp[1] = 0;
222       ierr       = MPI_Attr_put(*comm_out,Petsc_Tag_keyval,tagvalp);CHKERRQ(ierr);
223       ierr = PetscInfo3(0,"Duplicating a communicator %ld %ld max tags = %d\n",(long)comm_in,(long)*comm_out,*maxval);CHKERRQ(ierr);
224 
225       /* save PETSc communicator inside user communicator, so we can get it next time */
226       ierr = PetscMemcpy(&ptr,comm_out,sizeof(MPI_Comm));CHKERRQ(ierr);
227       ierr = MPI_Attr_put(comm_in,Petsc_InnerComm_keyval,ptr);CHKERRQ(ierr);
228       ierr = PetscMemcpy(&ptr,&comm_in,sizeof(MPI_Comm));CHKERRQ(ierr);
229       ierr = MPI_Attr_put(*comm_out,Petsc_OuterComm_keyval,ptr);CHKERRQ(ierr);
230     } else {
231       /*
232         We use PetscMemcpy() because casting from pointer to integer of different size is not allowed with some compilers
233       */
234       ierr = PetscMemcpy(comm_out,&ptr,sizeof(MPI_Comm));CHKERRQ(ierr);
235       ierr = MPI_Attr_get(*comm_out,Petsc_Tag_keyval,(void**)&tagvalp,(PetscMPIInt*)&flg);CHKERRQ(ierr);
236       if (!flg) {
237         SETERRQ(PETSC_ERR_PLIB,"Inner PETSc communicator does not have its tagvalp attribute set");
238       }
239       ierr = PetscInfo2(0,"Using internal PETSc communicator %ld %ld\n",(long)comm_in,(long)*comm_out);CHKERRQ(ierr);
240     }
241   } else {
242     *comm_out = comm_in;
243   }
244 
245 #if defined(PETSC_USE_DEBUG)
246   /*
247      Hanging here means that some processes have called PetscCommDuplicate() and others have not.
248      This likley means that a subset of processes in a MPI_Comm have attempted to create a PetscObject!
249      ALL processes that share a communicator MUST shared objects created from that communicator.
250   */
251   ierr = MPI_Barrier(comm_in);CHKERRQ(ierr);
252 #endif
253 
254   if (tagvalp[0] < 1) {
255     ierr = PetscInfo1(0,"Out of tags for object, starting to recycle. Comm reference count %d\n",tagvalp[1]);CHKERRQ(ierr);
256     ierr       = MPI_Attr_get(MPI_COMM_WORLD,MPI_TAG_UB,(void**)&maxval,(PetscMPIInt*)&flg);CHKERRQ(ierr);
257     if (!flg) {
258       SETERRQ(PETSC_ERR_LIB,"MPI error: MPI_Attr_get() is not returning a MPI_TAG_UB");
259     }
260     tagvalp[0] = *maxval - 128; /* hope that any still active tags were issued right at the beginning of the run */
261   }
262 
263   if (first_tag) {
264     *first_tag = tagvalp[0]--;
265     ierr = PetscInfo1(0,"  returning tag %ld\n",(long)*first_tag);CHKERRQ(ierr);
266   }
267   tagvalp[1]++; /* number of references to this comm */
268   PetscFunctionReturn(0);
269 }
270 
271 #undef __FUNCT__
272 #define __FUNCT__ "PetscCommDestroy"
273 /*@C
274    PetscCommDestroy - Frees communicator.  Use in conjunction with PetscCommDuplicate().
275 
276    Collective on MPI_Comm
277 
278    Input Parameter:
279 .  comm - the communicator to free
280 
281    Level: developer
282 
283    Concepts: communicator^destroy
284 
285 @*/
286 PetscErrorCode PETSC_DLLEXPORT PetscCommDestroy(MPI_Comm *comm)
287 {
288   PetscErrorCode ierr;
289   PetscMPIInt    *tagvalp;
290   PetscTruth     flg;
291   MPI_Comm       icomm = *comm,ocomm;
292   void           *ptr;
293 
294   PetscFunctionBegin;
295   if (Petsc_Tag_keyval == MPI_KEYVAL_INVALID) {
296     ierr = MPI_Keyval_create(MPI_NULL_COPY_FN,Petsc_DelTag,&Petsc_Tag_keyval,(void*)0);CHKERRQ(ierr);
297     ierr = MPI_Keyval_create(MPI_NULL_COPY_FN,Petsc_DelComm,&Petsc_InnerComm_keyval,(void*)0);CHKERRQ(ierr);
298     ierr = MPI_Keyval_create(MPI_NULL_COPY_FN,Petsc_DelComm,&Petsc_OuterComm_keyval,(void*)0);CHKERRQ(ierr);
299   }
300   ierr = MPI_Attr_get(icomm,Petsc_Tag_keyval,(void**)&tagvalp,(PetscMPIInt*)&flg);CHKERRQ(ierr);
301   if (!flg) {
302     ierr  = MPI_Attr_get(icomm,Petsc_InnerComm_keyval,&ptr,(PetscMPIInt*)&flg);CHKERRQ(ierr);
303     /*
304         We use PetscMemcpy() because casting from pointer to integer of different size is not allowed with some compilers
305     */
306     ierr = PetscMemcpy(&icomm,&ptr,sizeof(MPI_Comm));CHKERRQ(ierr);
307     if (!flg) {
308       PetscFunctionReturn(0);
309     }
310     ierr = MPI_Attr_get(icomm,Petsc_Tag_keyval,(void**)&tagvalp,(PetscMPIInt*)&flg);CHKERRQ(ierr);
311     if (!flg) {
312       SETERRQ(PETSC_ERR_ARG_CORRUPT,"Error freeing MPI_Comm, problem with corrupted memory");
313     }
314   }
315   tagvalp[1]--;
316   if (!tagvalp[1]) {
317 
318     ierr  = MPI_Attr_get(icomm,Petsc_OuterComm_keyval,&ptr,(PetscMPIInt*)&flg);CHKERRQ(ierr);
319     ierr = PetscMemcpy(&ocomm,&ptr,sizeof(MPI_Comm));CHKERRQ(ierr);
320 
321     if (flg) {
322       ierr = MPI_Attr_delete(ocomm,Petsc_InnerComm_keyval);CHKERRQ(ierr);
323     }
324 
325     ierr = PetscInfo1(0,"Deleting MPI_Comm %ld\n",(long)icomm);CHKERRQ(ierr);
326     ierr = MPI_Comm_free(&icomm);CHKERRQ(ierr);
327   }
328   PetscFunctionReturn(0);
329 }
330 
331