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 references of the communicator there, when it equals zero the communicator may be freed. 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 tag storage when a communicator is freed. 34 35 This is called by MPI, not by users. 36 37 Note: this is declared extern "C" because it is passed to MPI_Keyval_create 38 39 */ 40 PetscMPIInt PETSC_DLLEXPORT MPIAPI Petsc_DelTag(MPI_Comm comm,PetscMPIInt keyval,void* attr_val,void* extra_state) 41 { 42 PetscErrorCode ierr; 43 44 PetscFunctionBegin; 45 ierr = PetscInfo1(0,"Deleting tag data in an MPI_Comm %ld\n",(long)comm);if (ierr) PetscFunctionReturn((PetscMPIInt)ierr); 46 ierr = PetscFree(attr_val);if (ierr) PetscFunctionReturn((PetscMPIInt)ierr); 47 PetscFunctionReturn(MPI_SUCCESS); 48 } 49 EXTERN_C_END 50 51 EXTERN_C_BEGIN 52 #undef __FUNCT__ 53 #define __FUNCT__ "Petsc_DelComm" 54 /* 55 This does not actually free anything, it simply marks when a reference count to an internal MPI_Comm reaches zero and the 56 the external MPI_Comm drops its reference to the internal MPI_Comm 57 58 This is called by MPI, not by users. 59 60 Note: this is declared extern "C" because it is passed to MPI_Keyval_create 61 62 */ 63 PetscMPIInt PETSC_DLLEXPORT MPIAPI Petsc_DelComm(MPI_Comm comm,PetscMPIInt keyval,void* attr_val,void* extra_state) 64 { 65 PetscErrorCode ierr; 66 67 PetscFunctionBegin; 68 ierr = PetscInfo1(0,"Deleting PETSc communicator imbedded in a user MPI_Comm %ld\n",(long)comm);if (ierr) PetscFunctionReturn((PetscMPIInt)ierr); 69 /* actually don't delete anything because we cannot increase the reference count of the communicator anyways */ 70 PetscFunctionReturn(MPI_SUCCESS); 71 } 72 EXTERN_C_END 73 74 #undef __FUNCT__ 75 #define __FUNCT__ "PetscObjectGetNewTag" 76 /*@C 77 PetscObjectGetNewTag - Gets a unique new tag from a PETSc object. All 78 processors that share the object MUST call this routine EXACTLY the same 79 number of times. This tag should only be used with the current objects 80 communicator; do NOT use it with any other MPI communicator. 81 82 Collective on PetscObject 83 84 Input Parameter: 85 . obj - the PETSc object; this must be cast with a (PetscObject), for example, 86 PetscObjectGetNewTag((PetscObject)mat,&tag); 87 88 Output Parameter: 89 . tag - the new tag 90 91 Level: developer 92 93 Concepts: tag^getting 94 Concepts: message tag^getting 95 Concepts: MPI message tag^getting 96 97 .seealso: PetscCommGetNewTag() 98 @*/ 99 PetscErrorCode PETSC_DLLEXPORT PetscObjectGetNewTag(PetscObject obj,PetscMPIInt *tag) 100 { 101 PetscErrorCode ierr; 102 103 PetscFunctionBegin; 104 ierr = PetscCommGetNewTag(obj->comm,tag);CHKERRQ(ierr); 105 PetscFunctionReturn(0); 106 } 107 108 #undef __FUNCT__ 109 #define __FUNCT__ "PetscCommGetNewTag" 110 /*@ 111 PetscCommGetNewTag - Gets a unique new tag from a PETSc communicator. All 112 processors that share the communicator MUST call this routine EXACTLY the same 113 number of times. This tag should only be used with the current objects 114 communicator; do NOT use it with any other MPI communicator. 115 116 Collective on comm 117 118 Input Parameter: 119 . comm - the MPI communicator 120 121 Output Parameter: 122 . tag - the new tag 123 124 Level: developer 125 126 Concepts: tag^getting 127 Concepts: message tag^getting 128 Concepts: MPI message tag^getting 129 130 .seealso: PetscObjectGetNewTag(), PetscCommDuplicate() 131 @*/ 132 PetscErrorCode PETSC_DLLEXPORT PetscCommGetNewTag(MPI_Comm comm,PetscMPIInt *tag) 133 { 134 PetscErrorCode ierr; 135 PetscMPIInt *tagvalp=0,*maxval; 136 PetscTruth flg; 137 138 PetscFunctionBegin; 139 PetscValidIntPointer(tag,2); 140 141 if (Petsc_Tag_keyval == MPI_KEYVAL_INVALID) { 142 ierr = MPI_Keyval_create(MPI_NULL_COPY_FN,Petsc_DelTag,&Petsc_Tag_keyval,(void*)0);CHKERRQ(ierr); 143 ierr = MPI_Keyval_create(MPI_NULL_COPY_FN,Petsc_DelComm,&Petsc_InnerComm_keyval,(void*)0);CHKERRQ(ierr); 144 ierr = MPI_Keyval_create(MPI_NULL_COPY_FN,Petsc_DelComm,&Petsc_OuterComm_keyval,(void*)0);CHKERRQ(ierr); 145 } 146 147 ierr = MPI_Attr_get(comm,Petsc_Tag_keyval,(void**)&tagvalp,(PetscMPIInt*)&flg);CHKERRQ(ierr); 148 if (!flg) SETERRQ(PETSC_ERR_ARG_CORRUPT,"Bad MPI communicator supplied; must be a PETSc communicator"); 149 150 if (tagvalp[0] < 1) { 151 ierr = PetscInfo1(0,"Out of tags for object, starting to recycle. Comm reference count %d\n",tagvalp[1]);CHKERRQ(ierr); 152 ierr = MPI_Attr_get(MPI_COMM_WORLD,MPI_TAG_UB,(void**)&maxval,(PetscMPIInt*)&flg);CHKERRQ(ierr); 153 if (!flg) { 154 SETERRQ(PETSC_ERR_LIB,"MPI error: MPI_Attr_get() is not returning a MPI_TAG_UB"); 155 } 156 tagvalp[0] = *maxval - 128; /* hope that any still active tags were issued right at the beginning of the run */ 157 } 158 159 *tag = tagvalp[0]--; 160 #if defined(PETSC_USE_DEBUG) 161 /* 162 Hanging here means that some processes have called PetscCommGetNewTag() and others have not. 163 */ 164 ierr = MPI_Barrier(comm);CHKERRQ(ierr); 165 #endif 166 PetscFunctionReturn(0); 167 } 168 169 #undef __FUNCT__ 170 #define __FUNCT__ "PetscCommDuplicate" 171 /*@C 172 PetscCommDuplicate - Duplicates the communicator only if it is not already a PETSc 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 The internal MPI_Comm is used to perform all the MPI calls for PETSc, the outter MPI_Comm is a user 188 level MPI_Comm that may be performing communication for the user or other library and so IS NOT used by PETSc. 189 190 Level: developer 191 192 Concepts: communicator^duplicate 193 194 .seealso: PetscObjectGetNewTag(), PetscCommGetNewTag(), PetscCommDestroy() 195 @*/ 196 PetscErrorCode PETSC_DLLEXPORT PetscCommDuplicate(MPI_Comm comm_in,MPI_Comm *comm_out,PetscMPIInt* first_tag) 197 { 198 PetscErrorCode ierr; 199 PetscMPIInt *tagvalp,*maxval; 200 PetscTruth flg; 201 202 PetscFunctionBegin; 203 if (Petsc_Tag_keyval == MPI_KEYVAL_INVALID) { 204 ierr = MPI_Keyval_create(MPI_NULL_COPY_FN,Petsc_DelTag,&Petsc_Tag_keyval,(void*)0);CHKERRQ(ierr); 205 ierr = MPI_Keyval_create(MPI_NULL_COPY_FN,Petsc_DelComm,&Petsc_InnerComm_keyval,(void*)0);CHKERRQ(ierr); 206 ierr = MPI_Keyval_create(MPI_NULL_COPY_FN,Petsc_DelComm,&Petsc_OuterComm_keyval,(void*)0);CHKERRQ(ierr); 207 } 208 ierr = MPI_Attr_get(comm_in,Petsc_Tag_keyval,(void**)&tagvalp,(PetscMPIInt*)&flg);CHKERRQ(ierr); 209 210 if (!flg) { /* this is NOT a PETSc comm */ 211 void *ptr; 212 /* check if this communicator has a PETSc communicator imbedded in it */ 213 ierr = MPI_Attr_get(comm_in,Petsc_InnerComm_keyval,&ptr,(PetscMPIInt*)&flg);CHKERRQ(ierr); 214 if (!flg) { 215 /* This communicator is not yet known to this system, so we duplicate it and make an internal communicator */ 216 ierr = MPI_Comm_dup(comm_in,comm_out);CHKERRQ(ierr); 217 ierr = MPI_Attr_get(MPI_COMM_WORLD,MPI_TAG_UB,(void**)&maxval,(PetscMPIInt*)&flg);CHKERRQ(ierr); 218 if (!flg) { 219 SETERRQ(PETSC_ERR_LIB,"MPI error: MPI_Attr_get() is not returning a MPI_TAG_UB"); 220 } 221 ierr = PetscMalloc(2*sizeof(PetscMPIInt),&tagvalp);CHKERRQ(ierr); 222 tagvalp[0] = *maxval; 223 tagvalp[1] = 0; 224 ierr = MPI_Attr_put(*comm_out,Petsc_Tag_keyval,tagvalp);CHKERRQ(ierr); 225 ierr = PetscInfo3(0,"Duplicating a communicator %ld %ld max tags = %d\n",(long)comm_in,(long)*comm_out,*maxval);CHKERRQ(ierr); 226 227 /* save PETSc communicator inside user communicator, so we can get it next time */ 228 /* Use PetscMemcpy() because casting from pointer to integer of different size is not allowed with some compilers */ 229 ierr = PetscMemcpy(&ptr,comm_out,sizeof(MPI_Comm));CHKERRQ(ierr); 230 ierr = MPI_Attr_put(comm_in,Petsc_InnerComm_keyval,ptr);CHKERRQ(ierr); 231 /* Use PetscMemcpy() because casting from pointer to integer of different size is not allowed with some compilers */ 232 ierr = PetscMemcpy(&ptr,&comm_in,sizeof(MPI_Comm));CHKERRQ(ierr); 233 ierr = MPI_Attr_put(*comm_out,Petsc_OuterComm_keyval,ptr);CHKERRQ(ierr); 234 } else { 235 /* pull out the inner MPI_Comm and hand it back to the caller */ 236 /* Use PetscMemcpy() because casting from pointer to integer of different size is not allowed with some compilers */ 237 ierr = PetscMemcpy(comm_out,&ptr,sizeof(MPI_Comm));CHKERRQ(ierr); 238 ierr = MPI_Attr_get(*comm_out,Petsc_Tag_keyval,(void**)&tagvalp,(PetscMPIInt*)&flg);CHKERRQ(ierr); 239 if (!flg) { 240 SETERRQ(PETSC_ERR_PLIB,"Inner PETSc communicator does not have its tagvalp attribute set"); 241 } 242 ierr = PetscInfo2(0,"Using internal PETSc communicator %ld %ld\n",(long)comm_in,(long)*comm_out);CHKERRQ(ierr); 243 } 244 } else { 245 *comm_out = comm_in; 246 } 247 248 #if defined(PETSC_USE_DEBUG) 249 /* 250 Hanging here means that some processes have called PetscCommDuplicate() and others have not. 251 This likley means that a subset of processes in a MPI_Comm have attempted to create a PetscObject! 252 ALL processes that share a communicator MUST shared objects created from that communicator. 253 */ 254 ierr = MPI_Barrier(comm_in);CHKERRQ(ierr); 255 #endif 256 257 if (tagvalp[0] < 1) { 258 ierr = PetscInfo1(0,"Out of tags for object, starting to recycle. Comm reference count %d\n",tagvalp[1]);CHKERRQ(ierr); 259 ierr = MPI_Attr_get(MPI_COMM_WORLD,MPI_TAG_UB,(void**)&maxval,(PetscMPIInt*)&flg);CHKERRQ(ierr); 260 if (!flg) { 261 SETERRQ(PETSC_ERR_LIB,"MPI error: MPI_Attr_get() is not returning a MPI_TAG_UB"); 262 } 263 tagvalp[0] = *maxval - 128; /* hope that any still active tags were issued right at the beginning of the run */ 264 } 265 266 if (first_tag) { 267 *first_tag = tagvalp[0]--; 268 ierr = PetscInfo1(0," returning tag %ld\n",(long)*first_tag);CHKERRQ(ierr); 269 } 270 tagvalp[1]++; /* number of references to this comm */ 271 PetscFunctionReturn(0); 272 } 273 274 #undef __FUNCT__ 275 #define __FUNCT__ "PetscCommDestroy" 276 /*@C 277 PetscCommDestroy - Frees communicator. Use in conjunction with PetscCommDuplicate(). 278 279 Collective on MPI_Comm 280 281 Input Parameter: 282 . comm - the communicator to free 283 284 Level: developer 285 286 Concepts: communicator^destroy 287 288 .seealso: PetscCommDuplicate() 289 @*/ 290 PetscErrorCode PETSC_DLLEXPORT PetscCommDestroy(MPI_Comm *comm) 291 { 292 PetscErrorCode ierr; 293 PetscMPIInt *tagvalp; 294 PetscTruth flg; 295 MPI_Comm icomm = *comm,ocomm; 296 void *ptr; 297 298 PetscFunctionBegin; 299 if (Petsc_Tag_keyval == MPI_KEYVAL_INVALID) { 300 ierr = MPI_Keyval_create(MPI_NULL_COPY_FN,Petsc_DelTag,&Petsc_Tag_keyval,(void*)0);CHKERRQ(ierr); 301 ierr = MPI_Keyval_create(MPI_NULL_COPY_FN,Petsc_DelComm,&Petsc_InnerComm_keyval,(void*)0);CHKERRQ(ierr); 302 ierr = MPI_Keyval_create(MPI_NULL_COPY_FN,Petsc_DelComm,&Petsc_OuterComm_keyval,(void*)0);CHKERRQ(ierr); 303 } 304 ierr = MPI_Attr_get(icomm,Petsc_Tag_keyval,(void**)&tagvalp,(PetscMPIInt*)&flg);CHKERRQ(ierr); 305 if (!flg) { /* not a PETSc comm, check if it has an inner comm */ 306 ierr = MPI_Attr_get(icomm,Petsc_InnerComm_keyval,&ptr,(PetscMPIInt*)&flg);CHKERRQ(ierr); 307 if (!flg) { 308 SETERRQ(PETSC_ERR_ARG_CORRUPT,"MPI_Comm does not have tagvalues nor does it have inner MPI_Comm"); 309 } 310 /* Use PetscMemcpy() because casting from pointer to integer of different size is not allowed with some compilers */ 311 ierr = PetscMemcpy(&icomm,&ptr,sizeof(MPI_Comm));CHKERRQ(ierr); 312 ierr = MPI_Attr_get(icomm,Petsc_Tag_keyval,(void**)&tagvalp,(PetscMPIInt*)&flg);CHKERRQ(ierr); 313 if (!flg) { 314 SETERRQ(PETSC_ERR_ARG_CORRUPT,"Inner MPI_Comm does not have expected tagvalues, problem with corrupted memory"); 315 } 316 } 317 tagvalp[1]--; 318 if (!tagvalp[1]) { 319 320 /* if MPI_Comm has outter comm then remove reference to inner MPI_Comm from outter MPI_Comm */ 321 ierr = MPI_Attr_get(icomm,Petsc_OuterComm_keyval,&ptr,(PetscMPIInt*)&flg);CHKERRQ(ierr); 322 /* Use PetscMemcpy() because casting from pointer to integer of different size is not allowed with some compilers */ 323 ierr = PetscMemcpy(&ocomm,&ptr,sizeof(MPI_Comm));CHKERRQ(ierr); 324 if (flg) { 325 ierr = MPI_Attr_delete(ocomm,Petsc_InnerComm_keyval);CHKERRQ(ierr); 326 } 327 328 ierr = PetscInfo1(0,"Deleting PETSc MPI_Comm %ld\n",(long)icomm);CHKERRQ(ierr); 329 ierr = MPI_Comm_free(&icomm);CHKERRQ(ierr); 330 } 331 PetscFunctionReturn(0); 332 } 333 334