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