1 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 #include <petsc-private/threadcommimpl.h> 11 /* ---------------------------------------------------------------- */ 12 /* 13 A simple way to manage tags inside a communicator. 14 15 It uses the attributes to determine if a new communicator 16 is needed and to store the available tags. 17 18 */ 19 20 21 #undef __FUNCT__ 22 #define __FUNCT__ "PetscObjectGetNewTag" 23 /*@C 24 PetscObjectGetNewTag - Gets a unique new tag from a PETSc object. All 25 processors that share the object MUST call this routine EXACTLY the same 26 number of times. This tag should only be used with the current objects 27 communicator; do NOT use it with any other MPI communicator. 28 29 Collective on PetscObject 30 31 Input Parameter: 32 . obj - the PETSc object; this must be cast with a (PetscObject), for example, 33 PetscObjectGetNewTag((PetscObject)mat,&tag); 34 35 Output Parameter: 36 . tag - the new tag 37 38 Level: developer 39 40 Concepts: tag^getting 41 Concepts: message tag^getting 42 Concepts: MPI message tag^getting 43 44 .seealso: PetscCommGetNewTag() 45 @*/ 46 PetscErrorCode PetscObjectGetNewTag(PetscObject obj,PetscMPIInt *tag) 47 { 48 PetscErrorCode ierr; 49 50 PetscFunctionBegin; 51 ierr = PetscCommGetNewTag(obj->comm,tag);CHKERRQ(ierr); 52 PetscFunctionReturn(0); 53 } 54 55 #undef __FUNCT__ 56 #define __FUNCT__ "PetscCommGetNewTag" 57 /*@ 58 PetscCommGetNewTag - Gets a unique new tag from a PETSc communicator. All 59 processors that share the communicator MUST call this routine EXACTLY the same 60 number of times. This tag should only be used with the current objects 61 communicator; do NOT use it with any other MPI communicator. 62 63 Collective on comm 64 65 Input Parameter: 66 . comm - the MPI communicator 67 68 Output Parameter: 69 . tag - the new tag 70 71 Level: developer 72 73 Concepts: tag^getting 74 Concepts: message tag^getting 75 Concepts: MPI message tag^getting 76 77 .seealso: PetscObjectGetNewTag(), PetscCommDuplicate() 78 @*/ 79 PetscErrorCode PetscCommGetNewTag(MPI_Comm comm,PetscMPIInt *tag) 80 { 81 PetscErrorCode ierr; 82 PetscCommCounter *counter; 83 PetscMPIInt *maxval,flg; 84 85 PetscFunctionBegin; 86 PetscValidIntPointer(tag,2); 87 88 ierr = MPI_Attr_get(comm,Petsc_Counter_keyval,&counter,&flg);CHKERRQ(ierr); 89 if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_CORRUPT,"Bad MPI communicator supplied; must be a PETSc communicator"); 90 91 if (counter->tag < 1) { 92 ierr = PetscInfo1(0,"Out of tags for object, starting to recycle. Comm reference count %d\n",counter->refcount);CHKERRQ(ierr); 93 ierr = MPI_Attr_get(MPI_COMM_WORLD,MPI_TAG_UB,&maxval,&flg);CHKERRQ(ierr); 94 if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"MPI error: MPI_Attr_get() is not returning a MPI_TAG_UB"); 95 counter->tag = *maxval - 128; /* hope that any still active tags were issued right at the beginning of the run */ 96 } 97 98 *tag = counter->tag--; 99 #if defined(PETSC_USE_DEBUG) 100 /* 101 Hanging here means that some processes have called PetscCommGetNewTag() and others have not. 102 */ 103 ierr = MPI_Barrier(comm);CHKERRQ(ierr); 104 #endif 105 PetscFunctionReturn(0); 106 } 107 108 #undef __FUNCT__ 109 #define __FUNCT__ "PetscCommDuplicate" 110 /*@C 111 PetscCommDuplicate - Duplicates the communicator only if it is not already a PETSc communicator. 112 113 Collective on MPI_Comm 114 115 Input Parameters: 116 . comm_in - Input communicator 117 118 Output Parameters: 119 + comm_out - Output communicator. May be comm_in. 120 - first_tag - Tag available that has not already been used with this communicator (you may 121 pass in PETSC_NULL if you do not need a tag) 122 123 PETSc communicators are just regular MPI communicators that keep track of which 124 tags have been used to prevent tag conflict. If you pass a non-PETSc communicator into 125 a PETSc creation routine it will attach a private communicator for use in the objects communications. 126 The internal MPI_Comm is used to perform all the MPI calls for PETSc, the outer MPI_Comm is a user 127 level MPI_Comm that may be performing communication for the user or other library and so IS NOT used by PETSc. 128 129 Level: developer 130 131 Concepts: communicator^duplicate 132 133 .seealso: PetscObjectGetNewTag(), PetscCommGetNewTag(), PetscCommDestroy() 134 @*/ 135 PetscErrorCode PetscCommDuplicate(MPI_Comm comm_in,MPI_Comm *comm_out,PetscMPIInt* first_tag) 136 { 137 PetscErrorCode ierr; 138 PetscCommCounter *counter; 139 PetscMPIInt *maxval,flg; 140 PetscInt trank; 141 PetscThreadComm tcomm; 142 143 PetscFunctionBegin; 144 ierr = MPI_Attr_get(comm_in,Petsc_Counter_keyval,&counter,&flg);CHKERRQ(ierr); 145 146 if (!flg) { /* this is NOT a PETSc comm */ 147 void *ptr; 148 /* check if this communicator has a PETSc communicator imbedded in it */ 149 ierr = MPI_Attr_get(comm_in,Petsc_InnerComm_keyval,&ptr,&flg);CHKERRQ(ierr); 150 if (!flg) { 151 /* This communicator is not yet known to this system, so we duplicate it and make an internal communicator */ 152 ierr = MPI_Comm_dup(comm_in,comm_out);CHKERRQ(ierr); 153 ierr = MPI_Attr_get(MPI_COMM_WORLD,MPI_TAG_UB,&maxval,&flg);CHKERRQ(ierr); 154 if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"MPI error: MPI_Attr_get() is not returning a MPI_TAG_UB"); 155 ierr = PetscMalloc(sizeof(PetscCommCounter),&counter);CHKERRQ(ierr); 156 counter->tag = *maxval; 157 counter->refcount = 0; 158 counter->namecount = 0; 159 ierr = MPI_Attr_put(*comm_out,Petsc_Counter_keyval,counter);CHKERRQ(ierr); 160 ierr = PetscInfo3(0,"Duplicating a communicator %ld %ld max tags = %d\n",(long)comm_in,(long)*comm_out,*maxval);CHKERRQ(ierr); 161 162 /* save PETSc communicator inside user communicator, so we can get it next time */ 163 /* Use PetscMemcpy() because casting from pointer to integer of different size is not allowed with some compilers */ 164 ierr = PetscMemcpy(&ptr,comm_out,sizeof(MPI_Comm));CHKERRQ(ierr); 165 ierr = MPI_Attr_put(comm_in,Petsc_InnerComm_keyval,ptr);CHKERRQ(ierr); 166 /* Use PetscMemcpy() because casting from pointer to integer of different size is not allowed with some compilers */ 167 ierr = PetscMemcpy(&ptr,&comm_in,sizeof(MPI_Comm));CHKERRQ(ierr); 168 ierr = MPI_Attr_put(*comm_out,Petsc_OuterComm_keyval,ptr);CHKERRQ(ierr); 169 } else { 170 /* pull out the inner MPI_Comm and hand it back to the caller */ 171 /* Use PetscMemcpy() because casting from pointer to integer of different size is not allowed with some compilers */ 172 ierr = PetscMemcpy(comm_out,&ptr,sizeof(MPI_Comm));CHKERRQ(ierr); 173 ierr = MPI_Attr_get(*comm_out,Petsc_Counter_keyval,&counter,&flg);CHKERRQ(ierr); 174 if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Inner PETSc communicator does not have its tag/name counter attribute set"); 175 ierr = PetscInfo2(0,"Using internal PETSc communicator %ld %ld\n",(long)comm_in,(long)*comm_out);CHKERRQ(ierr); 176 } 177 } else { 178 *comm_out = comm_in; 179 } 180 181 #if defined(PETSC_USE_DEBUG) 182 /* 183 Hanging here means that some processes have called PetscCommDuplicate() and others have not. 184 This likley means that a subset of processes in a MPI_Comm have attempted to create a PetscObject! 185 ALL processes that share a communicator MUST shared objects created from that communicator. 186 */ 187 ierr = MPI_Barrier(comm_in);CHKERRQ(ierr); 188 #endif 189 190 if (counter->tag < 1) { 191 ierr = PetscInfo1(0,"Out of tags for object, starting to recycle. Comm reference count %d\n",counter->refcount);CHKERRQ(ierr); 192 ierr = MPI_Attr_get(MPI_COMM_WORLD,MPI_TAG_UB,&maxval,&flg);CHKERRQ(ierr); 193 if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"MPI error: MPI_Attr_get() is not returning a MPI_TAG_UB"); 194 counter->tag = *maxval - 128; /* hope that any still active tags were issued right at the beginning of the run */ 195 } 196 197 if (first_tag) { 198 *first_tag = counter->tag--; 199 } 200 201 ierr = MPI_Attr_get(*comm_out,Petsc_ThreadComm_keyval,(PetscThreadComm*)&tcomm,&flg);CHKERRQ(ierr); 202 if(!flg) { 203 /* Threadcomm does not exist on this communicator, get the global threadcomm and attach it to this communicator */ 204 ierr = PetscCommGetThreadComm(PETSC_COMM_WORLD,&tcomm);CHKERRQ(ierr); 205 ierr = PetscThreadCommAttach(*comm_out,tcomm);CHKERRQ(ierr); 206 } 207 /* Only the main thread updates counter->refcount */ 208 ierr = PetscThreadCommGetRank(tcomm,&trank);CHKERRQ(ierr); 209 if (!trank) counter->refcount++; /* number of references to this comm */ 210 211 PetscFunctionReturn(0); 212 } 213 214 #undef __FUNCT__ 215 #define __FUNCT__ "PetscCommDestroy" 216 /*@C 217 PetscCommDestroy - Frees communicator. Use in conjunction with PetscCommDuplicate(). 218 219 Collective on MPI_Comm 220 221 Input Parameter: 222 . comm - the communicator to free 223 224 Level: developer 225 226 Concepts: communicator^destroy 227 228 .seealso: PetscCommDuplicate() 229 @*/ 230 PetscErrorCode PetscCommDestroy(MPI_Comm *comm) 231 { 232 PetscErrorCode ierr; 233 PetscCommCounter *counter; 234 PetscMPIInt flg; 235 MPI_Comm icomm = *comm,ocomm; 236 void *ptr; 237 PetscThreadComm tcomm; 238 239 PetscFunctionBegin; 240 if (*comm == MPI_COMM_NULL) PetscFunctionReturn(0); 241 ierr = MPI_Attr_get(icomm,Petsc_Counter_keyval,&counter,&flg);CHKERRQ(ierr); 242 if (!flg) { /* not a PETSc comm, check if it has an inner comm */ 243 ierr = MPI_Attr_get(icomm,Petsc_InnerComm_keyval,&ptr,&flg);CHKERRQ(ierr); 244 if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_CORRUPT,"MPI_Comm does not have tag/name counter nor does it have inner MPI_Comm"); 245 /* Use PetscMemcpy() because casting from pointer to integer of different size is not allowed with some compilers */ 246 ierr = PetscMemcpy(&icomm,&ptr,sizeof(MPI_Comm));CHKERRQ(ierr); 247 ierr = MPI_Attr_get(icomm,Petsc_Counter_keyval,&counter,&flg);CHKERRQ(ierr); 248 if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_CORRUPT,"Inner MPI_Comm does not have expected tag/name counter, problem with corrupted memory"); 249 } 250 251 /* Only the main thread updates counter->refcount */ 252 ierr = MPI_Attr_get(icomm,Petsc_ThreadComm_keyval,(PetscThreadComm*)&tcomm,&flg);CHKERRQ(ierr); 253 if (flg) { 254 PetscInt trank; 255 ierr = PetscThreadCommGetRank(tcomm,&trank);CHKERRQ(ierr); 256 /* Only thread rank 0 updates the counter */ 257 if (!trank) counter->refcount--; 258 } else counter->refcount--; 259 260 if (!counter->refcount) { 261 /* if MPI_Comm has outer comm then remove reference to inner MPI_Comm from outer MPI_Comm */ 262 ierr = MPI_Attr_get(icomm,Petsc_OuterComm_keyval,&ptr,&flg);CHKERRQ(ierr); 263 if (flg) { 264 /* Use PetscMemcpy() because casting from pointer to integer of different size is not allowed with some compilers */ 265 ierr = PetscMemcpy(&ocomm,&ptr,sizeof(MPI_Comm));CHKERRQ(ierr); 266 ierr = MPI_Attr_get(ocomm,Petsc_InnerComm_keyval,&ptr,&flg);CHKERRQ(ierr); 267 if (flg) { 268 ierr = MPI_Attr_delete(ocomm,Petsc_InnerComm_keyval);CHKERRQ(ierr); 269 } else SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_CORRUPT,"Outer MPI_Comm %ld does not have expected reference to inner comm %d, problem with corrupted memory",(long int)ocomm,(long int)icomm); 270 } 271 272 ierr = PetscInfo1(0,"Deleting PETSc MPI_Comm %ld\n",(long)icomm);CHKERRQ(ierr); 273 ierr = MPI_Comm_free(&icomm);CHKERRQ(ierr); 274 } 275 *comm = MPI_COMM_NULL; 276 PetscFunctionReturn(0); 277 } 278 279 #undef __FUNCT__ 280 #define __FUNCT__ "PetscObjectsGetGlobalNumbering" 281 /*@C 282 PetscObjectsGetGlobalNumbering - computes a global numbering 283 of PetscObjects living on subcommunicators of a given communicator. 284 This results in a deadlock-free ordering of the subcommunicators 285 and, hence, the objects. 286 287 288 Collective on comm. 289 290 Input Parameters: 291 + comm - MPI_Comm 292 . len - length of objlist 293 - objlist - a list of PETSc objects living on subcommunicators of comm 294 (subcommunicator ordering is assumed to be deadlock-free) 295 296 Output Parameters: 297 + count - number of globally-distinct subcommunicators on objlist 298 . numbering - global numbers of objlist entries (allocated by user) 299 300 301 Level: developer 302 303 Concepts: MPI subcomm^numbering 304 305 @*/ 306 PetscErrorCode PetscObjectsGetGlobalNumbering(MPI_Comm comm, PetscInt len, PetscObject *objlist, PetscInt *count, PetscInt *numbering) 307 { 308 PetscErrorCode ierr; 309 PetscInt i, roots, offset; 310 PetscMPIInt size, rank; 311 PetscFunctionBegin; 312 PetscValidPointer(objlist,3); 313 PetscValidPointer(count,4); 314 PetscValidPointer(numbering,5); 315 ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr); 316 ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); 317 roots = 0; 318 for (i = 0; i < len; ++i) { 319 PetscMPIInt srank; 320 ierr = MPI_Comm_rank(objlist[i]->comm, &srank);CHKERRQ(ierr); 321 /* Am I the root of the i-th subcomm? */ 322 if (!srank) ++roots; 323 } 324 /* Obtain the sum of all roots -- the global number of distinct subcomms. */ 325 ierr = MPI_Allreduce(&roots,count,1,MPIU_INT,MPI_SUM,comm);CHKERRQ(ierr); 326 /* Now introduce a global numbering for subcomms, initially known only by subcomm roots. */ 327 /* 328 At the subcomm roots number the subcomms in the subcomm-root local manner, 329 and make it global by calculating the shift. 330 */ 331 ierr = MPI_Scan(&roots,&offset,1,MPIU_INT,MPI_SUM,comm);CHKERRQ(ierr); 332 offset -= roots; 333 /* Now we are ready to broadcast global subcomm numbers within each subcomm.*/ 334 /* 335 This is where the assumption of a deadlock-free ordering of the subcomms is assumed: 336 broadcast is collective on the subcomm. 337 */ 338 roots = 0; 339 for (i = 0; i < len; ++i) { 340 PetscMPIInt srank; 341 numbering[i] = offset + roots; /* only meaningful if !srank. */ 342 ierr = MPI_Comm_rank(objlist[i]->comm, &srank);CHKERRQ(ierr); 343 ierr = MPI_Bcast(numbering+i,1,MPIU_INT,0,objlist[i]->comm);CHKERRQ(ierr); 344 if (!srank) ++roots; 345 } 346 347 PetscFunctionReturn(0); 348 } 349