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 the system routine signal() 37 which is an extern "C" routine. 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 the system routine signal() 58 which is an extern "C" routine. 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 PETSc 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 PetscFunctionReturn(0); 158 } 159 160 #undef __FUNCT__ 161 #define __FUNCT__ "PetscCommSynchronizeTags" 162 PetscErrorCode PETSC_DLLEXPORT PetscCommSynchronizeTags(MPI_Comm comm) 163 { 164 PetscMPIInt *tagvalp = 0, tag; 165 PetscTruth flg; 166 PetscErrorCode ierr; 167 168 PetscFunctionBegin; 169 ierr = MPI_Attr_get(comm, Petsc_Tag_keyval, (void **) &tagvalp, (PetscMPIInt *) &flg);CHKERRQ(ierr); 170 if (!flg) { 171 MPI_Comm innerComm; 172 void *ptr; 173 174 /* check if this communicator has a PETSc communicator imbedded in it */ 175 ierr = MPI_Attr_get(comm, Petsc_InnerComm_keyval, &ptr, (PetscMPIInt*) &flg);CHKERRQ(ierr); 176 if (!flg) { 177 SETERRQ(PETSC_ERR_ARG_CORRUPT,"Bad MPI communicator supplied; must be a PETSc communicator"); 178 } else { 179 /* We use PetscMemcpy() because casting from pointer to integer of different size is not allowed with some compilers */ 180 ierr = PetscMemcpy(&innerComm, &ptr, sizeof(MPI_Comm));CHKERRQ(ierr); 181 ierr = MPI_Attr_get(innerComm, Petsc_Tag_keyval, (void **) &tagvalp, (PetscMPIInt *) &flg);CHKERRQ(ierr); 182 if (!flg) { 183 SETERRQ(PETSC_ERR_PLIB,"Inner PETSc communicator does not have its tagvalp attribute set"); 184 } 185 } 186 } 187 ierr = MPI_Allreduce(tagvalp, &tag, 1, MPI_INT, MPI_MIN, comm);CHKERRQ(ierr); 188 tagvalp[0] = tag; 189 ierr = PetscInfo2(0, "Reset tag for comm %ld to \n", (long) comm, tagvalp[0]);CHKERRQ(ierr); 190 PetscFunctionReturn(0); 191 } 192 193 #undef __FUNCT__ 194 #define __FUNCT__ "PetscCommCheckTags" 195 PetscErrorCode PETSC_DLLEXPORT PetscCommCheckTags(MPI_Comm comm) 196 { 197 PetscMPIInt *tagvalp = 0, tag; 198 PetscTruth flg; 199 PetscErrorCode ierr; 200 201 PetscFunctionBegin; 202 ierr = MPI_Attr_get(comm, Petsc_Tag_keyval, (void **) &tagvalp, (PetscMPIInt *) &flg);CHKERRQ(ierr); 203 if (!flg) { 204 MPI_Comm innerComm; 205 void *ptr; 206 207 /* check if this communicator has a PETSc communicator imbedded in it */ 208 ierr = MPI_Attr_get(comm, Petsc_InnerComm_keyval, &ptr, (PetscMPIInt*) &flg);CHKERRQ(ierr); 209 if (!flg) { 210 SETERRQ(PETSC_ERR_ARG_CORRUPT,"Bad MPI communicator supplied; must be a PETSc communicator"); 211 } else { 212 /* We use PetscMemcpy() because casting from pointer to integer of different size is not allowed with some compilers */ 213 ierr = PetscMemcpy(&innerComm, &ptr, sizeof(MPI_Comm));CHKERRQ(ierr); 214 ierr = MPI_Attr_get(innerComm, Petsc_Tag_keyval, (void **) &tagvalp, (PetscMPIInt *) &flg);CHKERRQ(ierr); 215 if (!flg) { 216 SETERRQ(PETSC_ERR_PLIB,"Inner PETSc communicator does not have its tagvalp attribute set"); 217 } 218 } 219 } 220 tag = tagvalp[0]; 221 ierr = MPI_Bcast(&tag, 1, MPI_INT, 0, comm);CHKERRQ(ierr); 222 if (tagvalp[0] != tag) { 223 SETERRQ2(PETSC_ERR_LIB, "Invalid tag %d should be %d", tagvalp[0], tag); 224 } 225 PetscFunctionReturn(0); 226 } 227 228 #undef __FUNCT__ 229 #define __FUNCT__ "PetscCommDuplicate" 230 /*@C 231 PetscCommDuplicate - Duplicates the communicator only if it is not already a PETSc 232 communicator. 233 234 Collective on MPI_Comm 235 236 Input Parameters: 237 . comm_in - Input communicator 238 239 Output Parameters: 240 + comm_out - Output communicator. May be comm_in. 241 - first_tag - Tag available that has not already been used with this communicator (you may 242 pass in PETSC_NULL if you do not need a tag) 243 244 PETSc communicators are just regular MPI communicators that keep track of which 245 tags have been used to prevent tag conflict. If you pass a non-PETSc communicator into 246 a PETSc creation routine it will attach a private communicator for use in the objects communications. 247 248 Level: developer 249 250 Concepts: communicator^duplicate 251 252 .seealso: PetscObjectGetNewTag(), PetscCommGetNewTag() 253 @*/ 254 PetscErrorCode PETSC_DLLEXPORT PetscCommDuplicate(MPI_Comm comm_in,MPI_Comm *comm_out,PetscMPIInt* first_tag) 255 { 256 PetscErrorCode ierr; 257 PetscMPIInt *tagvalp,*maxval; 258 PetscTruth flg; 259 260 PetscFunctionBegin; 261 if (Petsc_Tag_keyval == MPI_KEYVAL_INVALID) { 262 ierr = MPI_Keyval_create(MPI_NULL_COPY_FN,Petsc_DelTag,&Petsc_Tag_keyval,(void*)0);CHKERRQ(ierr); 263 ierr = MPI_Keyval_create(MPI_NULL_COPY_FN,Petsc_DelComm,&Petsc_InnerComm_keyval,(void*)0);CHKERRQ(ierr); 264 ierr = MPI_Keyval_create(MPI_NULL_COPY_FN,Petsc_DelComm,&Petsc_OuterComm_keyval,(void*)0);CHKERRQ(ierr); 265 } 266 ierr = MPI_Attr_get(comm_in,Petsc_Tag_keyval,(void**)&tagvalp,(PetscMPIInt*)&flg);CHKERRQ(ierr); 267 268 if (!flg) { 269 void *ptr; 270 /* check if this communicator has a PETSc communicator imbedded in it */ 271 ierr = MPI_Attr_get(comm_in,Petsc_InnerComm_keyval,&ptr,(PetscMPIInt*)&flg);CHKERRQ(ierr); 272 if (!flg) { 273 /* This communicator is not yet known to this system, so we duplicate it and set its value */ 274 ierr = MPI_Comm_dup(comm_in,comm_out);CHKERRQ(ierr); 275 ierr = MPI_Attr_get(MPI_COMM_WORLD,MPI_TAG_UB,(void**)&maxval,(PetscMPIInt*)&flg);CHKERRQ(ierr); 276 if (!flg) { 277 SETERRQ(PETSC_ERR_LIB,"MPI error: MPI_Attr_get() is not returning a MPI_TAG_UB"); 278 } 279 ierr = PetscMalloc(2*sizeof(PetscMPIInt),&tagvalp);CHKERRQ(ierr); 280 tagvalp[0] = *maxval; 281 tagvalp[1] = 0; 282 ierr = MPI_Attr_put(*comm_out,Petsc_Tag_keyval,tagvalp);CHKERRQ(ierr); 283 ierr = PetscInfo3(0,"Duplicating a communicator %ld %ld max tags = %d\n",(long)comm_in,(long)*comm_out,*maxval);CHKERRQ(ierr); 284 285 /* save PETSc communicator inside user communicator, so we can get it next time */ 286 ierr = PetscMemcpy(&ptr,comm_out,sizeof(MPI_Comm));CHKERRQ(ierr); 287 ierr = MPI_Attr_put(comm_in,Petsc_InnerComm_keyval,ptr);CHKERRQ(ierr); 288 ierr = PetscMemcpy(&ptr,&comm_in,sizeof(MPI_Comm));CHKERRQ(ierr); 289 ierr = MPI_Attr_put(*comm_out,Petsc_OuterComm_keyval,ptr);CHKERRQ(ierr); 290 } else { 291 /* 292 We use PetscMemcpy() because casting from pointer to integer of different size is not allowed with some compilers 293 */ 294 ierr = PetscMemcpy(comm_out,&ptr,sizeof(MPI_Comm));CHKERRQ(ierr); 295 ierr = MPI_Attr_get(*comm_out,Petsc_Tag_keyval,(void**)&tagvalp,(PetscMPIInt*)&flg);CHKERRQ(ierr); 296 if (!flg) { 297 SETERRQ(PETSC_ERR_PLIB,"Inner PETSc communicator does not have its tagvalp attribute set"); 298 } 299 ierr = PetscInfo2(0,"Using internal PETSc communicator %ld %ld\n",(long)comm_in,(long)*comm_out);CHKERRQ(ierr); 300 } 301 } else { 302 #if defined(PETSC_USE_DEBUG) 303 PetscMPIInt tag; 304 ierr = MPI_Allreduce(tagvalp,&tag,1,MPI_INT,MPI_BOR,comm_in);CHKERRQ(ierr); 305 if (tag != tagvalp[0]) { 306 SETERRQ(PETSC_ERR_ARG_CORRUPT,"Communicator was used on subset of processors."); 307 } 308 #endif 309 *comm_out = comm_in; 310 } 311 312 if (tagvalp[0] < 1) { 313 ierr = PetscInfo1(0,"Out of tags for object, starting to recycle. Comm reference count %d\n",tagvalp[1]);CHKERRQ(ierr); 314 ierr = MPI_Attr_get(MPI_COMM_WORLD,MPI_TAG_UB,(void**)&maxval,(PetscMPIInt*)&flg);CHKERRQ(ierr); 315 if (!flg) { 316 SETERRQ(PETSC_ERR_LIB,"MPI error: MPI_Attr_get() is not returning a MPI_TAG_UB"); 317 } 318 tagvalp[0] = *maxval - 128; /* hope that any still active tags were issued right at the beginning of the run */ 319 } 320 321 if (first_tag) { 322 *first_tag = tagvalp[0]--; 323 } 324 tagvalp[1]++; /* number of references to this comm */ 325 PetscFunctionReturn(0); 326 } 327 328 #undef __FUNCT__ 329 #define __FUNCT__ "PetscCommDestroy" 330 /*@C 331 PetscCommDestroy - Frees communicator. Use in conjunction with PetscCommDuplicate(). 332 333 Collective on MPI_Comm 334 335 Input Parameter: 336 . comm - the communicator to free 337 338 Level: developer 339 340 Concepts: communicator^destroy 341 342 @*/ 343 PetscErrorCode PETSC_DLLEXPORT PetscCommDestroy(MPI_Comm *comm) 344 { 345 PetscErrorCode ierr; 346 PetscMPIInt *tagvalp; 347 PetscTruth flg; 348 MPI_Comm icomm = *comm,ocomm; 349 void *ptr; 350 351 PetscFunctionBegin; 352 if (Petsc_Tag_keyval == MPI_KEYVAL_INVALID) { 353 ierr = MPI_Keyval_create(MPI_NULL_COPY_FN,Petsc_DelTag,&Petsc_Tag_keyval,(void*)0);CHKERRQ(ierr); 354 ierr = MPI_Keyval_create(MPI_NULL_COPY_FN,Petsc_DelComm,&Petsc_InnerComm_keyval,(void*)0);CHKERRQ(ierr); 355 ierr = MPI_Keyval_create(MPI_NULL_COPY_FN,Petsc_DelComm,&Petsc_OuterComm_keyval,(void*)0);CHKERRQ(ierr); 356 } 357 ierr = MPI_Attr_get(icomm,Petsc_Tag_keyval,(void**)&tagvalp,(PetscMPIInt*)&flg);CHKERRQ(ierr); 358 if (!flg) { 359 ierr = MPI_Attr_get(icomm,Petsc_InnerComm_keyval,&ptr,(PetscMPIInt*)&flg);CHKERRQ(ierr); 360 /* 361 We use PetscMemcpy() because casting from pointer to integer of different size is not allowed with some compilers 362 */ 363 ierr = PetscMemcpy(&icomm,&ptr,sizeof(MPI_Comm));CHKERRQ(ierr); 364 if (!flg) { 365 PetscFunctionReturn(0); 366 } 367 ierr = MPI_Attr_get(icomm,Petsc_Tag_keyval,(void**)&tagvalp,(PetscMPIInt*)&flg);CHKERRQ(ierr); 368 if (!flg) { 369 SETERRQ(PETSC_ERR_ARG_CORRUPT,"Error freeing MPI_Comm, problem with corrupted memory"); 370 } 371 } 372 tagvalp[1]--; 373 if (!tagvalp[1]) { 374 375 ierr = MPI_Attr_get(icomm,Petsc_OuterComm_keyval,&ptr,(PetscMPIInt*)&flg);CHKERRQ(ierr); 376 ierr = PetscMemcpy(&ocomm,&ptr,sizeof(MPI_Comm));CHKERRQ(ierr); 377 378 if (flg) { 379 ierr = MPI_Attr_delete(ocomm,Petsc_InnerComm_keyval);CHKERRQ(ierr); 380 } 381 382 ierr = PetscInfo1(0,"Deleting MPI_Comm %ld\n",(long)icomm);CHKERRQ(ierr); 383 ierr = MPI_Comm_free(&icomm);CHKERRQ(ierr); 384 } 385 PetscFunctionReturn(0); 386 } 387 388