1 #include <petsc/private/deviceimpl.h> /*I "petscdevice.h" I*/ 2 #include "objpool.hpp" 3 4 /* Define the allocator */ 5 struct PetscDeviceContextAllocator : Petsc::Allocator<PetscDeviceContext> 6 { 7 static PetscInt PetscDeviceContextID; 8 9 PETSC_NODISCARD PetscErrorCode create(PetscDeviceContext *dctx) noexcept 10 { 11 PetscDeviceContext dc; 12 PetscErrorCode ierr; 13 14 PetscFunctionBegin; 15 ierr = PetscNew(&dc);CHKERRQ(ierr); 16 dc->id = PetscDeviceContextID++; 17 dc->idle = PETSC_TRUE; 18 dc->streamType = PETSC_STREAM_DEFAULT_BLOCKING; 19 *dctx = dc; 20 PetscFunctionReturn(0); 21 } 22 23 PETSC_NODISCARD PetscErrorCode destroy(PetscDeviceContext &dctx) const noexcept 24 { 25 PetscErrorCode ierr; 26 27 PetscFunctionBegin; 28 if (PetscUnlikelyDebug(dctx->numChildren)) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Device context still has %D un-restored children, must call PetscDeviceContextRestore() on all children before destroying",dctx->numChildren); 29 if (dctx->ops->destroy) {ierr = (*dctx->ops->destroy)(dctx);CHKERRQ(ierr);} 30 ierr = PetscDeviceDestroy(&dctx->device);CHKERRQ(ierr); 31 ierr = PetscFree(dctx->childIDs);CHKERRQ(ierr); 32 ierr = PetscFree(dctx);CHKERRQ(ierr); 33 PetscFunctionReturn(0); 34 } 35 36 PETSC_NODISCARD PetscErrorCode reset(PetscDeviceContext &dctx) const noexcept 37 { 38 PetscErrorCode ierr; 39 40 PetscFunctionBegin; 41 /* don't deallocate the child array, rather just zero it out */ 42 ierr = PetscArrayzero(dctx->childIDs,dctx->maxNumChildren);CHKERRQ(ierr); 43 dctx->setup = PETSC_FALSE; 44 dctx->numChildren = 0; 45 dctx->idle = PETSC_TRUE; 46 dctx->streamType = PETSC_STREAM_DEFAULT_BLOCKING; 47 PetscFunctionReturn(0); 48 } 49 50 PETSC_NODISCARD PetscErrorCode finalize(void) noexcept 51 { 52 PetscFunctionBegin; 53 PetscDeviceContextID = 0; 54 PetscFunctionReturn(0); 55 } 56 }; 57 PetscInt PetscDeviceContextAllocator::PetscDeviceContextID = 0; 58 59 static Petsc::ObjectPool<PetscDeviceContext,PetscDeviceContextAllocator> contextPool; 60 61 /*@C 62 PetscDeviceContextCreate - Creates a PetscDeviceContext 63 64 Not Collective, Asynchronous 65 66 Ouput Paramemters: 67 . dctx - The PetscDeviceContext 68 69 Notes: 70 Unlike almost every other PETSc class it is advised that most users use 71 PetscDeviceContextDuplicate() rather than this routine to create new contexts. Contexts 72 of different types are incompatible with one another; using 73 PetscDeviceContextDuplicate() ensures compatible types. 74 75 Level: beginner 76 77 .seealso: PetscDeviceContextDuplicate(), PetscDeviceContextSetDevice(), 78 PetscDeviceContextSetStreamType(), PetscDeviceContextSetUp(), 79 PetscDeviceContextSetFromOptions(), PetscDeviceContextDestroy() 80 @*/ 81 PetscErrorCode PetscDeviceContextCreate(PetscDeviceContext *dctx) 82 { 83 PetscErrorCode ierr; 84 85 PetscFunctionBegin; 86 PetscValidPointer(dctx,1); 87 ierr = PetscDeviceInitializePackage();CHKERRQ(ierr); 88 ierr = contextPool.get(*dctx);CHKERRQ(ierr); 89 PetscFunctionReturn(0); 90 } 91 92 /*@C 93 PetscDeviceContextDestroy - Frees a PetscDeviceContext 94 95 Not Collective, Asynchronous 96 97 Input Parameters: 98 . dctx - The PetscDeviceContext 99 100 Notes: 101 No implicit synchronization occurs due to this routine, all resources are released completely asynchronously 102 w.r.t. the host. If one needs to guarantee access to the data produced on this contexts stream one should perform the 103 appropriate synchronization before calling this routine. 104 105 Developer Notes: 106 The context is never actually "destroyed", only returned to an ever growing pool of 107 contexts. There are currently no safeguards on the size of the pool, this should perhaps 108 be implemented. 109 110 Level: beginner 111 112 .seealso: PetscDeviceContextCreate(), PetscDeviceContextSetDevice(), PetscDeviceContextSetUp(), PetscDeviceContextSynchronize() 113 @*/ 114 PetscErrorCode PetscDeviceContextDestroy(PetscDeviceContext *dctx) 115 { 116 PetscErrorCode ierr; 117 118 PetscFunctionBegin; 119 if (!*dctx) PetscFunctionReturn(0); 120 /* use move assignment whenever possible */ 121 ierr = contextPool.reclaim(std::move(*dctx));CHKERRQ(ierr); 122 PetscFunctionReturn(0); 123 } 124 125 /*@C 126 PetscDeviceContextSetStreamType - Set the implementation type of the underlying stream for a PetscDeviceContext 127 128 Not Collective, Asynchronous 129 130 Input Paramaters: 131 + dctx - The PetscDeviceContext 132 - type - The PetscStreamType 133 134 Notes: 135 See PetscStreamType in include/petscdevicetypes.h for more information on the available 136 types and their interactions. If the PetscDeviceContext was previously set up and stream 137 type was changed, you must call PetscDeviceContextSetUp() again after this routine. 138 139 Level: intermediate 140 141 .seealso: PetscDeviceContextGetStreamType(), PetscDeviceContextCreate(), PetscDeviceContextSetUp(), PetscDeviceContextSetFromOptions() 142 @*/ 143 PetscErrorCode PetscDeviceContextSetStreamType(PetscDeviceContext dctx, PetscStreamType type) 144 { 145 PetscFunctionBegin; 146 PetscValidDeviceContext(dctx,1); 147 PetscValidStreamType(type,2); 148 /* only need to do complex swapping if the object has already been setup */ 149 if (dctx->setup && (dctx->streamType != type)) { 150 PetscErrorCode ierr; 151 152 ierr = (*dctx->ops->changestreamtype)(dctx,type);CHKERRQ(ierr); 153 dctx->setup = PETSC_FALSE; 154 } 155 dctx->streamType = type; 156 PetscFunctionReturn(0); 157 } 158 159 /*@C 160 PetscDeviceContextGetStreamType - Get the implementation type of the underlying stream for a PetscDeviceContext 161 162 Not Collective, Asynchronous 163 164 Input Paramater: 165 . dctx - The PetscDeviceContext 166 167 Output Parameter: 168 . type - The PetscStreamType 169 170 Notes: 171 See PetscStreamType in include/petscdevicetypes.h for more information on the available types and their interactions 172 173 Level: intermediate 174 175 .seealso: PetscDeviceContextSetStreamType(), PetscDeviceContextCreate(), PetscDeviceContextSetFromOptions() 176 @*/ 177 PetscErrorCode PetscDeviceContextGetStreamType(PetscDeviceContext dctx, PetscStreamType *type) 178 { 179 PetscFunctionBegin; 180 PetscValidDeviceContext(dctx,1); 181 PetscValidIntPointer(type,2); 182 *type = dctx->streamType; 183 PetscFunctionReturn(0); 184 } 185 186 /*@C 187 PetscDeviceContextSetDevice - Set the underlying device for the PetscDeviceContext 188 189 Not Collective, Possibly Synchronous 190 191 Input Paramaters: 192 + dctx - The PetscDeviceContext 193 - device - The PetscDevice 194 195 Notes: 196 This routine is effectively PetscDeviceContext's "set-type" (so every PetscDeviceContext 197 must also have an attached PetscDevice). Unlike the usual set-type semantics, it is 198 not stricly necessary to set a contexts device to enable usage, any created device 199 contexts will always come equipped with the "default" device. 200 201 This routine may initialize the backend device and incur synchronization. 202 203 Level: intermediate 204 205 .seealso: PetscDeviceCreate(), PetscDeviceConfigure(), PetscDeviceContextGetDevice() 206 @*/ 207 PetscErrorCode PetscDeviceContextSetDevice(PetscDeviceContext dctx, PetscDevice device) 208 { 209 PetscErrorCode ierr; 210 211 PetscFunctionBegin; 212 PetscValidDeviceContext(dctx,1); 213 PetscValidDevice(device,2); 214 if (dctx->device == device) PetscFunctionReturn(0); 215 ierr = PetscDeviceDestroy(&dctx->device);CHKERRQ(ierr); 216 ierr = PetscMemzero(dctx->ops,sizeof(*dctx->ops));CHKERRQ(ierr); 217 ierr = (*device->ops->createcontext)(dctx);CHKERRQ(ierr); 218 dctx->device = PetscDeviceReference(device); 219 dctx->setup = PETSC_FALSE; 220 PetscFunctionReturn(0); 221 } 222 223 /*@C 224 PetscDeviceContextGetDevice - Get the underlying PetscDevice for a PetscDeviceContext 225 226 Not Collective, Asynchronous 227 228 Input Parameter: 229 . dctx - the PetscDeviceContext 230 231 Output Parameter: 232 . device - The PetscDevice 233 234 Notes: 235 This is a borrowed reference, the user should not destroy the device. 236 237 .seealso: PetscDeviceContextSetDevice(), PetscDevice 238 @*/ 239 PetscErrorCode PetscDeviceContextGetDevice(PetscDeviceContext dctx, PetscDevice *device) 240 { 241 PetscFunctionBegin; 242 PetscValidDeviceContext(dctx,1); 243 PetscValidPointer(device,2); 244 *device = dctx->device; 245 PetscFunctionReturn(0); 246 } 247 248 /*@C 249 PetscDeviceContextSetUp - Prepares a PetscDeviceContext for use 250 251 Not Collective, Asynchronous 252 253 Intput Parameter: 254 . dctx - The PetscDeviceContext 255 256 Developer Notes: 257 This routine is usually the stage where a PetscDeviceContext acquires device-side data structures such as streams, 258 events, and (possibly) handles. 259 260 Level: beginner 261 262 .seealso: PetscDeviceContextCreate(), PetscDeviceContextSetDevice(), PetscDeviceContextDestroy(), PetscDeviceContextSetFromOptions() 263 @*/ 264 PetscErrorCode PetscDeviceContextSetUp(PetscDeviceContext dctx) 265 { 266 PetscErrorCode ierr; 267 268 PetscFunctionBegin; 269 PetscValidDeviceContext(dctx,1); 270 if (!dctx->device) { 271 ierr = PetscInfo2(NULL,"PetscDeviceContext %d did not have an explicitly attached PetscDevice, using default with type %s\n",dctx->id,PetscDeviceKinds[PETSC_DEVICE_DEFAULT]);CHKERRQ(ierr); 272 ierr = PetscDeviceContextSetDevice(dctx,PetscDeviceDefault_Internal());CHKERRQ(ierr); 273 } 274 if (dctx->setup) PetscFunctionReturn(0); 275 ierr = (*dctx->ops->setup)(dctx);CHKERRQ(ierr); 276 dctx->setup = PETSC_TRUE; 277 PetscFunctionReturn(0); 278 } 279 280 /*@C 281 PetscDeviceContextDuplicate - Duplicates a PetscDeviceContext object 282 283 Not Collective, Asynchronous 284 285 Input Parameter: 286 . dctx - The PetscDeviceContext to duplicate 287 288 Output Paramter: 289 . strmdup - The duplicated PetscDeviceContext 290 291 Notes: 292 This is a shorthand method for creating a PetscDeviceContext with the exact same 293 settings as another. Note however that the duplicated PetscDeviceContext does not "share" 294 any of the underlying data with the original, (including its current stream-state) they 295 are completely separate objects. 296 297 Level: beginner 298 299 .seealso: PetscDeviceContextCreate(), PetscDeviceContextSetDevice(), PetscDeviceContextSetStreamType() 300 @*/ 301 PetscErrorCode PetscDeviceContextDuplicate(PetscDeviceContext dctx, PetscDeviceContext *dctxdup) 302 { 303 PetscErrorCode ierr; 304 305 PetscFunctionBegin; 306 PetscValidDeviceContext(dctx,1); 307 PetscValidPointer(dctxdup,2); 308 ierr = PetscDeviceContextCreate(dctxdup);CHKERRQ(ierr); 309 ierr = PetscDeviceContextSetDevice(*dctxdup,dctx->device);CHKERRQ(ierr); 310 ierr = PetscDeviceContextSetStreamType(*dctxdup,dctx->streamType);CHKERRQ(ierr); 311 ierr = PetscDeviceContextSetUp(*dctxdup);CHKERRQ(ierr); 312 PetscFunctionReturn(0); 313 } 314 315 /*@C 316 PetscDeviceContextQueryIdle - Returns whether or not a PetscDeviceContext is idle 317 318 Not Collective, Asynchronous 319 320 Input Parameter: 321 . dctx - The PetscDeviceContext object 322 323 Output Parameter: 324 . idle - PETSC_TRUE if PetscDeviceContext has NO work, PETSC_FALSE if it has work 325 326 Notes: 327 This routine only refers a singular context and does NOT take any of its children into account. That is, if dctx is 328 idle but has dependents who do have work, this routine still returns PETSC_TRUE. 329 330 Results of PetscDeviceContextQueryIdle() are cached on return, allowing this function to be called repeatedly in an 331 efficient manner. When debug mode is enabled this cache is verified on every call to 332 this routine, but is blindly believed when debugging is disabled. 333 334 Level: intermediate 335 336 .seealso: PetscDeviceContextCreate(), PetscDeviceContextWaitForContext(), PetscDeviceContextFork() 337 @*/ 338 PetscErrorCode PetscDeviceContextQueryIdle(PetscDeviceContext dctx, PetscBool *idle) 339 { 340 PetscErrorCode ierr; 341 342 PetscFunctionBegin; 343 PetscValidDeviceContext(dctx,1); 344 PetscValidBoolPointer(idle,2); 345 if (dctx->idle) { 346 *idle = PETSC_TRUE; 347 ierr = PetscDeviceContextValidateIdle_Internal(dctx);CHKERRQ(ierr); 348 } else { 349 ierr = (*dctx->ops->query)(dctx,idle);CHKERRQ(ierr); 350 dctx->idle = *idle; 351 } 352 PetscFunctionReturn(0); 353 } 354 355 /*@C 356 PetscDeviceContextWaitForContext - Make one context wait for another context to finish 357 358 Not Collective, Asynchronous 359 360 Input Parameters: 361 + dctxa - The PetscDeviceContext object that is waiting 362 - dctxb - The PetscDeviceContext object that is being waited on 363 364 Notes: 365 Serializes two PetscDeviceContexts. This routine uses only the state of dctxb at the moment this routine was 366 called, so any future work queued will not affect dctxa. It is safe to pass the same context to both arguments. 367 368 Level: beginner 369 370 .seealso: PetscDeviceContextCreate(), PetscDeviceContextQueryIdle(), PetscDeviceContextJoin() 371 @*/ 372 PetscErrorCode PetscDeviceContextWaitForContext(PetscDeviceContext dctxa, PetscDeviceContext dctxb) 373 { 374 PetscErrorCode ierr; 375 376 PetscFunctionBegin; 377 PetscCheckCompatibleDeviceContexts(dctxa,1,dctxb,2); 378 if (dctxa == dctxb) PetscFunctionReturn(0); 379 if (dctxb->idle) { 380 /* No need to do the extra function lookup and event record if the stream were waiting on isn't doing anything */ 381 ierr = PetscDeviceContextValidateIdle_Internal(dctxb);CHKERRQ(ierr); 382 } else { 383 ierr = (*dctxa->ops->waitforctx)(dctxa,dctxb);CHKERRQ(ierr); 384 } 385 PetscFunctionReturn(0); 386 } 387 388 /*@C 389 PetscDeviceContextFork - Create a set of dependent child contexts from a parent context 390 391 Not Collective, Asynchronous 392 393 Input Parameters: 394 + dctx - The parent PetscDeviceContext 395 - n - The number of children to create 396 397 Output Parameter: 398 . dsub - The created child context(s) 399 400 Notes: 401 This routine creates n edges of a DAG from a source node which are causally dependent on the source node, meaning 402 that work queued on child contexts will not start until the parent context finishes its work. This accounts for work 403 queued on the parent up until calling this function, any subsequent work enqueued on the parent has no effect on the children. 404 405 Any children created with this routine have their lifetimes bounded by the parent. That is, the parent context expects 406 to free all of it's children (and ONLY its children) before itself is freed. 407 408 DAG representation: 409 .vb 410 time -> 411 412 -> dctx \----> dctx ------> 413 \---> dsub[0] ---> 414 \--> ... -------> 415 \-> dsub[n-1] -> 416 .ve 417 418 Level: intermediate 419 420 .seealso: PetscDeviceContextJoin(), PetscDeviceContextSynchronize(), PetscDeviceContextQueryIdle() 421 @*/ 422 PetscErrorCode PetscDeviceContextFork(PetscDeviceContext dctx, PetscInt n, PetscDeviceContext **dsub) 423 { 424 #if defined(PETSC_USE_DEBUG) && defined(PETSC_USE_INFO) 425 const PetscInt nBefore = n; 426 static std::string idList; 427 #endif 428 PetscDeviceContext *dsubTmp = nullptr; 429 PetscInt i = 0; 430 PetscErrorCode ierr; 431 432 PetscFunctionBegin; 433 PetscValidDeviceContext(dctx,1); 434 PetscValidPointer(dsub,3); 435 if (PetscUnlikelyDebug(n < 0)) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Number of contexts requested %D < 0",n); 436 #if defined(PETSC_USE_DEBUG) && defined(PETSC_USE_INFO) 437 /* reserve 4 chars per id, 2 for number and 2 for ', ' separator */ 438 idList.reserve(4*n); 439 #endif 440 /* update child totals */ 441 dctx->numChildren += n; 442 /* now to find out if we have room */ 443 if (dctx->numChildren > dctx->maxNumChildren) { 444 /* no room, either from having too many kids or not having any */ 445 if (dctx->childIDs) { 446 /* have existing children, must reallocate them */ 447 ierr = PetscRealloc(dctx->numChildren*sizeof(*dctx->childIDs),&dctx->childIDs);CHKERRQ(ierr); 448 /* clear the extra memory since realloc doesn't do it for us */ 449 ierr = PetscArrayzero((dctx->childIDs)+(dctx->maxNumChildren),(dctx->numChildren)-(dctx->maxNumChildren));CHKERRQ(ierr); 450 } else { 451 /* have no children */ 452 ierr = PetscCalloc1(dctx->numChildren,&dctx->childIDs);CHKERRQ(ierr); 453 } 454 /* update total number of children */ 455 dctx->maxNumChildren = dctx->numChildren; 456 } 457 ierr = PetscMalloc1(n,&dsubTmp);CHKERRQ(ierr); 458 while (n) { 459 /* empty child slot */ 460 if (!(dctx->childIDs[i])) { 461 /* create the child context in the image of its parent */ 462 ierr = PetscDeviceContextDuplicate(dctx,dsubTmp+i);CHKERRQ(ierr); 463 ierr = PetscDeviceContextWaitForContext(dsubTmp[i],dctx);CHKERRQ(ierr); 464 /* register the child with its parent */ 465 dctx->childIDs[i] = dsubTmp[i]->id; 466 #if defined(PETSC_USE_DEBUG) && defined(PETSC_USE_INFO) 467 idList += std::to_string(dsubTmp[i]->id); 468 if (n != 1) idList += ", "; 469 #endif 470 --n; 471 } 472 ++i; 473 } 474 #if defined(PETSC_USE_DEBUG) && defined(PETSC_USE_INFO) 475 ierr = PetscInfo3(NULL,"Forked %D children from parent %D with IDs: %s\n",nBefore,dctx->id,idList.c_str());CHKERRQ(ierr); 476 /* resets the size but doesn't deallocate the memory */ 477 idList.clear(); 478 #endif 479 /* pass the children back to caller */ 480 *dsub = dsubTmp; 481 PetscFunctionReturn(0); 482 } 483 484 /*@C 485 PetscDeviceContextJoin - Converge a set of child contexts 486 487 Not Collective, Asynchronous 488 489 Input Parameters: 490 + dctx - A PetscDeviceContext to converge on 491 . n - The number of sub contexts to converge 492 . joinMode - The type of join to perform 493 - dsub - The sub contexts to converge 494 495 Notes: 496 If PetscDeviceContextFork() creates n edges from a source node which all depend on the 497 source node, then this routine is the exact mirror. That is, it creates a node 498 (represented in dctx) which recieves n edges (and optionally destroys them) which is 499 dependent on the completion of all incoming edges. 500 501 If joinMode is PETSC_DEVICE_CONTEXT_JOIN_DESTROY all contexts in dsub will be destroyed 502 by this routine. Thus all sub contexts must have been created with the dctx passed to 503 this routine. 504 505 if joinMode is PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC dctx waits for all sub contexts but the 506 sub contexts do not wait for one another afterwards. 507 508 If joinMode is PETSC_DEVICE_CONTEXT_JOIN_SYNC all sub contexts will additionally 509 wait on dctx after converging. This has the effect of "synchronizing" the outgoing 510 edges. 511 512 DAG representations: 513 If joinMode is PETSC_DEVICE_CONTEXT_JOIN_DESTROY 514 .vb 515 time -> 516 517 -> dctx ---------/- dctx -> 518 -> dsub[0] -----/ 519 -> ... -------/ 520 -> dsub[n-1] -/ 521 .ve 522 If joinMode is PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC 523 .vb 524 time -> 525 526 -> dctx ---------/- dctx -> 527 -> dsub[0] -----/---------> 528 -> ... -------/----------> 529 -> dsub[n-1] -/-----------> 530 .ve 531 If joinMode is PETSC_DEVICE_CONTEXT_JOIN_SYNC 532 .vb 533 time -> 534 535 -> dctx ---------/- dctx -\----> dctx ------> 536 -> dsub[0] -----/ \---> dsub[0] ---> 537 -> ... -------/ \--> ... -------> 538 -> dsub[n-1] -/ \-> dsub[n-1] -> 539 .ve 540 541 Level: intermediate 542 543 .seealso: PetscDeviceContextFork(), PetscDeviceContextSynchronize(), PetscDeviceContextJoinMode 544 @*/ 545 PetscErrorCode PetscDeviceContextJoin(PetscDeviceContext dctx, PetscInt n, PetscDeviceContextJoinMode joinMode, PetscDeviceContext **dsub) 546 { 547 #if defined(PETSC_USE_DEBUG) && defined(PETSC_USE_INFO) 548 static std::string idList; 549 #endif 550 PetscErrorCode ierr; 551 552 PetscFunctionBegin; 553 /* validity of dctx is checked in the wait-for loop */ 554 PetscValidPointer(dsub,4); 555 if (PetscUnlikelyDebug(n < 0)) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Number of contexts merged %D < 0",n); 556 #if defined(PETSC_USE_DEBUG) && defined(PETSC_USE_INFO) 557 /* reserve 4 chars per id, 2 for number and 2 for ', ' separator */ 558 idList.reserve(4*n); 559 #endif 560 /* first dctx waits on all the incoming edges */ 561 for (PetscInt i = 0; i < n; ++i) { 562 PetscCheckCompatibleDeviceContexts(dctx,1,(*dsub)[i],4); 563 ierr = PetscDeviceContextWaitForContext(dctx,(*dsub)[i]);CHKERRQ(ierr); 564 #if defined(PETSC_USE_DEBUG) && defined(PETSC_USE_INFO) 565 idList += std::to_string((*dsub)[i]->id); 566 if (i+1 < n) idList += ", "; 567 #endif 568 } 569 570 /* now we handle the aftermath */ 571 switch (joinMode) { 572 case PETSC_DEVICE_CONTEXT_JOIN_DESTROY: 573 { 574 PetscInt j = 0; 575 576 if (PetscUnlikelyDebug(n > dctx->numChildren)) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Trying to destroy %D children of a parent context that only has %D children, likely trying to restore to wrong parent",n,dctx->numChildren); 577 /* update child count while it's still fresh in memory */ 578 dctx->numChildren -= n; 579 for (PetscInt i = 0; i < dctx->maxNumChildren; ++i) { 580 if (dctx->childIDs[i] && (dctx->childIDs[i] == (*dsub)[j]->id)) { 581 /* child is one of ours, can destroy it */ 582 ierr = PetscDeviceContextDestroy((*dsub)+j);CHKERRQ(ierr); 583 /* reset the child slot */ 584 dctx->childIDs[i] = 0; 585 if (++j == n) break; 586 } 587 } 588 /* gone through the loop but did not find every child, if this triggers (or well, doesn't) on perf-builds we leak the remaining contexts memory */ 589 if (PetscUnlikelyDebug(j != n)) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"%D contexts still remain after destroy, this may be because you are trying to restore to the wrong parent context, or the device contexts are not in the same order as they were checked out out in.",n-j); 590 ierr = PetscFree(*dsub);CHKERRQ(ierr); 591 } 592 break; 593 case PETSC_DEVICE_CONTEXT_JOIN_SYNC: 594 for (PetscInt i = 0; i < n; ++i) { 595 ierr = PetscDeviceContextWaitForContext((*dsub)[i],dctx);CHKERRQ(ierr); 596 } 597 case PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC: 598 break; 599 default: 600 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Unknown PetscDeviceContextJoinMode given"); 601 break; 602 } 603 604 #if defined(PETSC_USE_DEBUG) && defined(PETSC_USE_INFO) 605 ierr = PetscInfo4(NULL,"Joined %D ctxs to ctx %D, mode %s with IDs: %s\n",n,dctx->id,PetscDeviceContextJoinModes[joinMode],idList.c_str());CHKERRQ(ierr); 606 idList.clear(); 607 #endif 608 PetscFunctionReturn(0); 609 } 610 611 /*@C 612 PetscDeviceContextSynchronize - Block the host until all work queued on or associated with a PetscDeviceContext has finished 613 614 Not Collective, Synchronous 615 616 Input Parameters: 617 . dctx - The PetscDeviceContext to synchronize 618 619 Level: beginner 620 621 .seealso: PetscDeviceContextFork(), PetscDeviceContextJoin(), PetscDeviceContextQueryIdle() 622 @*/ 623 PetscErrorCode PetscDeviceContextSynchronize(PetscDeviceContext dctx) 624 { 625 PetscErrorCode ierr; 626 627 PetscFunctionBegin; 628 PetscValidDeviceContext(dctx,1); 629 /* if it isn't setup there is nothing to sync on */ 630 if (dctx->setup) {ierr = (*dctx->ops->synchronize)(dctx);CHKERRQ(ierr);} 631 dctx->idle = PETSC_TRUE; 632 PetscFunctionReturn(0); 633 } 634 635 static PetscDeviceContext globalContext = nullptr; 636 static PetscBool globalContextSetup = PETSC_FALSE; 637 static PetscStreamType defaultStreamType = PETSC_STREAM_DEFAULT_BLOCKING; 638 639 /* automatically registered to PetscFinalize() when first context is instantiated, do not 640 call */ 641 static PetscErrorCode PetscDeviceContextDestroyGlobalContext_Private(void) 642 { 643 PetscErrorCode ierr; 644 645 PetscFunctionBegin; 646 ierr = PetscDeviceContextSynchronize(globalContext);CHKERRQ(ierr); 647 ierr = PetscDeviceContextDestroy(&globalContext);CHKERRQ(ierr); 648 /* reset everything to defaults */ 649 defaultStreamType = PETSC_STREAM_DEFAULT_BLOCKING; 650 globalContextSetup = PETSC_FALSE; 651 PetscFunctionReturn(0); 652 } 653 654 /* creates and initializes the root context in PetscInitialize() but does not call 655 SetUp() as the user may wish to change types after PetscInitialize() */ 656 PetscErrorCode PetscDeviceContextInitializeRootContext_Internal(MPI_Comm comm, const char prefix[]) 657 { 658 PetscErrorCode ierr; 659 660 PetscFunctionBegin; 661 ierr = PetscInfo1(NULL,"Initializing root PetscDeviceContext with PetscDeviceKind %s\n",PetscDeviceKinds[PETSC_DEVICE_DEFAULT]);CHKERRQ(ierr); 662 ierr = PetscDeviceContextCreate(&globalContext);CHKERRQ(ierr); 663 if (PetscUnlikelyDebug(globalContext->id != 0)) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"The root current PetscDeviceContext should have id = 0, however it has id = %D",globalContext->id); 664 ierr = PetscDeviceContextSetDevice(globalContext,PetscDeviceDefault_Internal());CHKERRQ(ierr); 665 ierr = PetscDeviceContextSetStreamType(globalContext,defaultStreamType);CHKERRQ(ierr); 666 ierr = PetscDeviceContextSetFromOptions(comm,prefix,globalContext);CHKERRQ(ierr); 667 ierr = PetscRegisterFinalize(PetscDeviceContextDestroyGlobalContext_Private);CHKERRQ(ierr); 668 PetscFunctionReturn(0); 669 } 670 671 /*@C 672 PetscDeviceContextGetCurrentContext - Get the current active PetscDeviceContext 673 674 Not Collective, Asynchronous 675 676 Output Parameter: 677 . dctx - The PetscDeviceContext 678 679 Notes: 680 The user generally should not destroy contexts retrieved with this routine unless they themselves have created 681 them. There exists no protection against destroying the root context. 682 683 Developer Notes: 684 This routine creates the "root" context the first time it is called, registering its 685 destructor to PetscFinalize(). The root context is synchronized before being destroyed. 686 687 Level: beginner 688 689 .seealso: PetscDeviceContextSetCurrentContext(), PetscDeviceContextFork(), 690 PetscDeviceContextJoin(), PetscDeviceContextCreate() 691 @*/ 692 PetscErrorCode PetscDeviceContextGetCurrentContext(PetscDeviceContext *dctx) 693 { 694 PetscFunctionBegin; 695 PetscValidPointer(dctx,1); 696 if (PetscUnlikely(!globalContextSetup)) { 697 PetscErrorCode ierr; 698 699 /* if there is no available device backend, PetscDeviceInitializePackage() will fire a 700 PETSC_ERR_SUP_SYS error. */ 701 ierr = PetscDeviceInitializePackage();CHKERRQ(ierr); 702 ierr = PetscDeviceContextSetUp(globalContext);CHKERRQ(ierr); 703 globalContextSetup = PETSC_TRUE; 704 } 705 *dctx = globalContext; 706 PetscFunctionReturn(0); 707 } 708 709 /*@C 710 PetscDeviceContextSetCurrentContext - Set the current active PetscDeviceContext 711 712 Not Collective, Asynchronous 713 714 Input Parameter: 715 . dctx - The PetscDeviceContext 716 717 Notes: 718 The old context is not stored in any way by this routine; if one is overriding a context that they themselves do not 719 control, one should take care to temporarily store it by calling PetscDeviceContextGetCurrentContext() before calling 720 this routine. 721 722 Level: beginner 723 724 .seealso: PetscDeviceContextGetCurrentContext(), PetscDeviceContextFork(), 725 PetscDeviceContextJoin(), PetscDeviceContextCreate() 726 @*/ 727 PetscErrorCode PetscDeviceContextSetCurrentContext(PetscDeviceContext dctx) 728 { 729 PetscErrorCode ierr; 730 731 PetscFunctionBegin; 732 PetscValidDeviceContext(dctx,1); 733 globalContext = dctx; 734 ierr = PetscInfo1(NULL,"Set global device context id %D\n",dctx->id);CHKERRQ(ierr); 735 PetscFunctionReturn(0); 736 } 737 738 /*@C 739 PetscDeviceContextSetFromOptions - Configure a PetscDeviceContext from the options database 740 741 Collective on comm, Asynchronous 742 743 Input Parameters: 744 + comm - MPI communicator on which to query the options database 745 . prefix - prefix to prepend to all options database queries, NULL if not needed 746 - dctx - The PetscDeviceContext to configure 747 748 Output Parameter: 749 . dctx - The PetscDeviceContext 750 751 Options Database: 752 . -device_context_device_kind - the kind of PetscDevice to attach by default - PetscDeviceKind 753 . -device_context_stream_type - type of stream to create inside the PetscDeviceContext - 754 PetscDeviceContextSetStreamType() 755 756 Level: beginner 757 758 .seealso: PetscDeviceContextSetStreamType(), PetscDeviceContextSetDevice() 759 @*/ 760 PetscErrorCode PetscDeviceContextSetFromOptions(MPI_Comm comm, const char prefix[], PetscDeviceContext dctx) 761 { 762 PetscBool flag; 763 PetscInt stype,dkind; 764 PetscErrorCode ierr; 765 766 PetscFunctionBegin; 767 if (prefix) {PetscValidCharPointer(prefix,2);} 768 PetscValidDeviceContext(dctx,3); 769 ierr = PetscOptionsBegin(comm,prefix,"PetscDeviceContext Options","Sys");CHKERRQ(ierr); 770 ierr = PetscOptionsEList("-device_context_device_kind","Underlying PetscDevice","PetscDeviceContextSetDevice",PetscDeviceKinds+1,PETSC_DEVICE_MAX-1,dctx->device ? PetscDeviceKinds[dctx->device->kind] : PetscDeviceKinds[PETSC_DEVICE_DEFAULT],&dkind,&flag);CHKERRQ(ierr); 771 if (flag) { 772 ierr = PetscDeviceContextSetDevice(dctx,PetscDeviceDefaultKind_Internal(static_cast<PetscDeviceKind>(dkind+1)));CHKERRQ(ierr); 773 } 774 ierr = PetscOptionsEList("-device_context_stream_type","PetscDeviceContext PetscStreamType","PetscDeviceContextSetStreamType",PetscStreamTypes,3,PetscStreamTypes[dctx->streamType],&stype,&flag);CHKERRQ(ierr); 775 if (flag) { 776 ierr = PetscDeviceContextSetStreamType(dctx,static_cast<PetscStreamType>(stype));CHKERRQ(ierr); 777 } 778 ierr = PetscOptionsEnd();CHKERRQ(ierr); 779 PetscFunctionReturn(0); 780 } 781