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