10e6b6b59SJacob Faibussowitsch #include "petscdevice_interface_internal.hpp" /*I <petscdevice.h> I*/ 20e6b6b59SJacob Faibussowitsch #include <petsc/private/viewerimpl.h> // _p_PetscViewer for PetscObjectCast() 3030f984aSJacob Faibussowitsch 40e6b6b59SJacob Faibussowitsch #include <petsc/private/cpp/object_pool.hpp> 50e6b6b59SJacob Faibussowitsch #include <petsc/private/cpp/utility.hpp> 60e6b6b59SJacob Faibussowitsch #include <petsc/private/cpp/array.hpp> 7a4af0ceeSJacob Faibussowitsch 80e6b6b59SJacob Faibussowitsch #include <vector> 90e6b6b59SJacob Faibussowitsch #include <string> // std::to_string among other things 10a4af0ceeSJacob Faibussowitsch 11030f984aSJacob Faibussowitsch /* Define the allocator */ 12146a86ebSJacob Faibussowitsch class PetscDeviceContextConstructor : public Petsc::ConstructorInterface<_p_PetscDeviceContext, PetscDeviceContextConstructor> { 130e6b6b59SJacob Faibussowitsch public: 14089fb57cSJacob Faibussowitsch PetscErrorCode construct_(PetscDeviceContext dctx) const noexcept 15d71ae5a4SJacob Faibussowitsch { 16030f984aSJacob Faibussowitsch PetscFunctionBegin; 17146a86ebSJacob Faibussowitsch PetscCall(PetscArrayzero(dctx, 1)); 18146a86ebSJacob Faibussowitsch PetscCall(PetscHeaderInitialize_Private(dctx, PETSC_DEVICE_CONTEXT_CLASSID, "PetscDeviceContext", "PetscDeviceContext", "Sys", PETSC_COMM_SELF, PetscDeviceContextDestroy, PetscDeviceContextView)); 19*dcf958e2SJacob Faibussowitsch PetscCallCXX(PetscObjectCast(dctx)->cpp = new CxxData{dctx}); 20146a86ebSJacob Faibussowitsch PetscCall(underlying().reset(dctx, false)); 213ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 22030f984aSJacob Faibussowitsch } 23030f984aSJacob Faibussowitsch 24089fb57cSJacob Faibussowitsch static PetscErrorCode destroy_(PetscDeviceContext dctx) noexcept 25d71ae5a4SJacob Faibussowitsch { 26030f984aSJacob Faibussowitsch PetscFunctionBegin; 27bf025ffbSJacob Faibussowitsch PetscAssert(!dctx->numChildren, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Device context still has %" PetscInt_FMT " un-joined children, must call PetscDeviceContextJoin() with all children before destroying", dctx->numChildren); 28dbbe0bcdSBarry Smith PetscTryTypeMethod(dctx, destroy); 299566063dSJacob Faibussowitsch PetscCall(PetscDeviceDestroy(&dctx->device)); 309566063dSJacob Faibussowitsch PetscCall(PetscFree(dctx->childIDs)); 310e6b6b59SJacob Faibussowitsch delete CxxDataCast(dctx); 32146a86ebSJacob Faibussowitsch PetscCall(PetscHeaderDestroy_Private(PetscObjectCast(dctx), PETSC_FALSE)); 333ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 34030f984aSJacob Faibussowitsch } 35030f984aSJacob Faibussowitsch 36089fb57cSJacob Faibussowitsch static PetscErrorCode reset_(PetscDeviceContext dctx, bool zero = true) noexcept 37d71ae5a4SJacob Faibussowitsch { 38030f984aSJacob Faibussowitsch PetscFunctionBegin; 390e6b6b59SJacob Faibussowitsch if (zero) { 400e6b6b59SJacob Faibussowitsch // reset the device if the user set it 41146a86ebSJacob Faibussowitsch if (Petsc::util::exchange(dctx->usersetdevice, PETSC_FALSE)) { 420e6b6b59SJacob Faibussowitsch PetscTryTypeMethod(dctx, destroy); 430e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceDestroy(&dctx->device)); 440e6b6b59SJacob Faibussowitsch PetscCall(PetscArrayzero(dctx->ops, 1)); 450e6b6b59SJacob Faibussowitsch dctx->data = nullptr; 460e6b6b59SJacob Faibussowitsch } 470e6b6b59SJacob Faibussowitsch PetscCall(PetscHeaderReset_Internal(PetscObjectCast(dctx))); 48030f984aSJacob Faibussowitsch dctx->numChildren = 0; 490e6b6b59SJacob Faibussowitsch dctx->setup = PETSC_FALSE; 500e6b6b59SJacob Faibussowitsch // don't deallocate the child array, rather just zero it out 510e6b6b59SJacob Faibussowitsch PetscCall(PetscArrayzero(dctx->childIDs, dctx->maxNumChildren)); 520e6b6b59SJacob Faibussowitsch PetscCall(CxxDataCast(dctx)->clear()); 53*dcf958e2SJacob Faibussowitsch PetscCall(CxxDataCast(dctx)->reset_self(dctx)); 540e6b6b59SJacob Faibussowitsch } 55030f984aSJacob Faibussowitsch dctx->streamType = PETSC_STREAM_DEFAULT_BLOCKING; 563ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 57030f984aSJacob Faibussowitsch } 58146a86ebSJacob Faibussowitsch 59*dcf958e2SJacob Faibussowitsch static PetscErrorCode invalidate_(PetscDeviceContext dctx) noexcept 60*dcf958e2SJacob Faibussowitsch { 61*dcf958e2SJacob Faibussowitsch PetscFunctionBegin; 62*dcf958e2SJacob Faibussowitsch PetscCall(CxxDataCast(dctx)->reset_self(dctx)); 63*dcf958e2SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 64*dcf958e2SJacob Faibussowitsch } 65030f984aSJacob Faibussowitsch }; 66030f984aSJacob Faibussowitsch 67146a86ebSJacob Faibussowitsch static Petsc::ObjectPool<_p_PetscDeviceContext, PetscDeviceContextConstructor> contextPool; 68030f984aSJacob Faibussowitsch 6910450e9eSJacob Faibussowitsch // PetscClangLinter pragma disable: -fdoc-section-header-unknown 70030f984aSJacob Faibussowitsch /*@C 71811af0c4SBarry Smith PetscDeviceContextCreate - Creates a `PetscDeviceContext` 72030f984aSJacob Faibussowitsch 730e6b6b59SJacob Faibussowitsch Not Collective 74030f984aSJacob Faibussowitsch 75d5b43468SJose E. Roman Output Parameter: 76811af0c4SBarry Smith . dctx - The `PetscDeviceContext` 77030f984aSJacob Faibussowitsch 782fe279fdSBarry Smith Level: beginner 792fe279fdSBarry Smith 80811af0c4SBarry Smith Note: 81030f984aSJacob Faibussowitsch Unlike almost every other PETSc class it is advised that most users use 820e6b6b59SJacob Faibussowitsch `PetscDeviceContextDuplicate()` rather than this routine to create new contexts. Contexts of 830e6b6b59SJacob Faibussowitsch different types are incompatible with one another; using `PetscDeviceContextDuplicate()` 840e6b6b59SJacob Faibussowitsch ensures compatible types. 850e6b6b59SJacob Faibussowitsch 860e6b6b59SJacob Faibussowitsch DAG representation: 870e6b6b59SJacob Faibussowitsch .vb 880e6b6b59SJacob Faibussowitsch time -> 890e6b6b59SJacob Faibussowitsch 900e6b6b59SJacob Faibussowitsch |= CALL =| - dctx -> 910e6b6b59SJacob Faibussowitsch .ve 92030f984aSJacob Faibussowitsch 930e6b6b59SJacob Faibussowitsch .N ASYNC_API 940e6b6b59SJacob Faibussowitsch 95db781477SPatrick Sanan .seealso: `PetscDeviceContextDuplicate()`, `PetscDeviceContextSetDevice()`, 96db781477SPatrick Sanan `PetscDeviceContextSetStreamType()`, `PetscDeviceContextSetUp()`, 970e6b6b59SJacob Faibussowitsch `PetscDeviceContextSetFromOptions()`, `PetscDeviceContextView()`, `PetscDeviceContextDestroy()` 98030f984aSJacob Faibussowitsch @*/ 99d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextCreate(PetscDeviceContext *dctx) 100d71ae5a4SJacob Faibussowitsch { 101030f984aSJacob Faibussowitsch PetscFunctionBegin; 1024f572ea9SToby Isaac PetscAssertPointer(dctx, 1); 1039566063dSJacob Faibussowitsch PetscCall(PetscDeviceInitializePackage()); 1046a4a1270SPierre Jolivet PetscCall(PetscLogEventBegin(DCONTEXT_Create, nullptr, nullptr, nullptr, nullptr)); 1050e6b6b59SJacob Faibussowitsch PetscCall(contextPool.allocate(dctx)); 1066a4a1270SPierre Jolivet PetscCall(PetscLogEventEnd(DCONTEXT_Create, nullptr, nullptr, nullptr, nullptr)); 1073ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 108030f984aSJacob Faibussowitsch } 109030f984aSJacob Faibussowitsch 11010450e9eSJacob Faibussowitsch // PetscClangLinter pragma disable: -fdoc-section-header-unknown 111030f984aSJacob Faibussowitsch /*@C 112811af0c4SBarry Smith PetscDeviceContextDestroy - Frees a `PetscDeviceContext` 113030f984aSJacob Faibussowitsch 1140e6b6b59SJacob Faibussowitsch Not Collective 115030f984aSJacob Faibussowitsch 1162fe279fdSBarry Smith Input Parameter: 117811af0c4SBarry Smith . dctx - The `PetscDeviceContext` 118030f984aSJacob Faibussowitsch 1192fe279fdSBarry Smith Level: beginner 1202fe279fdSBarry Smith 1210e6b6b59SJacob Faibussowitsch Notes: 1220e6b6b59SJacob Faibussowitsch No implicit synchronization occurs due to this routine, all resources are released completely 1230e6b6b59SJacob Faibussowitsch asynchronously w.r.t. the host. If one needs to guarantee access to the data produced on 1240e6b6b59SJacob Faibussowitsch `dctx`'s stream the user is responsible for calling `PetscDeviceContextSynchronize()` before 1250e6b6b59SJacob Faibussowitsch calling this routine. 126030f984aSJacob Faibussowitsch 127da81f932SPierre Jolivet DAG representation: 1280e6b6b59SJacob Faibussowitsch .vb 1290e6b6b59SJacob Faibussowitsch time -> 1300e6b6b59SJacob Faibussowitsch 1310e6b6b59SJacob Faibussowitsch -> dctx - |= CALL =| 1320e6b6b59SJacob Faibussowitsch .ve 1330e6b6b59SJacob Faibussowitsch 1340e6b6b59SJacob Faibussowitsch Developer Notes: 1350e6b6b59SJacob Faibussowitsch `dctx` is never actually "destroyed" in the classical sense. It is returned to an ever 1360e6b6b59SJacob Faibussowitsch growing pool of `PetscDeviceContext`s. There are currently no limits on the size of the pool, 1370e6b6b59SJacob Faibussowitsch this should perhaps be implemented. 138030f984aSJacob Faibussowitsch 1390e6b6b59SJacob Faibussowitsch .N ASYNC_API 1400e6b6b59SJacob Faibussowitsch 1410e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextSetDevice()`, 1420e6b6b59SJacob Faibussowitsch `PetscDeviceContextSetUp()`, `PetscDeviceContextSynchronize()` 143030f984aSJacob Faibussowitsch @*/ 144d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextDestroy(PetscDeviceContext *dctx) 145d71ae5a4SJacob Faibussowitsch { 146030f984aSJacob Faibussowitsch PetscFunctionBegin; 1474f572ea9SToby Isaac PetscAssertPointer(dctx, 1); 1483ba16761SJacob Faibussowitsch if (!*dctx) PetscFunctionReturn(PETSC_SUCCESS); 1496a4a1270SPierre Jolivet PetscCall(PetscLogEventBegin(DCONTEXT_Destroy, nullptr, nullptr, nullptr, nullptr)); 1500e6b6b59SJacob Faibussowitsch if (--(PetscObjectCast(*dctx)->refct) <= 0) { 1510e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextCheckNotOrphaned_Internal(*dctx)); 152146a86ebSJacob Faibussowitsch PetscCall(contextPool.deallocate(dctx)); 1530e6b6b59SJacob Faibussowitsch } 1546a4a1270SPierre Jolivet PetscCall(PetscLogEventEnd(DCONTEXT_Destroy, nullptr, nullptr, nullptr, nullptr)); 155bf025ffbSJacob Faibussowitsch *dctx = nullptr; 1563ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 157030f984aSJacob Faibussowitsch } 158030f984aSJacob Faibussowitsch 159030f984aSJacob Faibussowitsch /*@C 1600e6b6b59SJacob Faibussowitsch PetscDeviceContextSetStreamType - Set the implementation type of the underlying stream for a 1610e6b6b59SJacob Faibussowitsch `PetscDeviceContext` 162030f984aSJacob Faibussowitsch 1630e6b6b59SJacob Faibussowitsch Not Collective 164030f984aSJacob Faibussowitsch 16501d2d390SJose E. Roman Input Parameters: 166811af0c4SBarry Smith + dctx - The `PetscDeviceContext` 167811af0c4SBarry Smith - type - The `PetscStreamType` 168030f984aSJacob Faibussowitsch 1692fe279fdSBarry Smith Level: beginner 1702fe279fdSBarry Smith 1712fe279fdSBarry Smith Note: 172811af0c4SBarry Smith See `PetscStreamType` in `include/petscdevicetypes.h` for more information on the available 1730e6b6b59SJacob Faibussowitsch types and their interactions. If the `PetscDeviceContext` was previously set up and stream 174811af0c4SBarry Smith type was changed, you must call `PetscDeviceContextSetUp()` again after this routine. 175030f984aSJacob Faibussowitsch 1760e6b6b59SJacob Faibussowitsch .seealso: `PetscStreamType`, `PetscDeviceContextGetStreamType()`, `PetscDeviceContextCreate()`, 1770e6b6b59SJacob Faibussowitsch `PetscDeviceContextSetUp()`, `PetscDeviceContextSetFromOptions()` 178030f984aSJacob Faibussowitsch @*/ 179d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetStreamType(PetscDeviceContext dctx, PetscStreamType type) 180d71ae5a4SJacob Faibussowitsch { 181030f984aSJacob Faibussowitsch PetscFunctionBegin; 1820e6b6b59SJacob Faibussowitsch // do not use getoptionalnullcontext here since we do not want the user to change the stream 1830e6b6b59SJacob Faibussowitsch // type 184030f984aSJacob Faibussowitsch PetscValidDeviceContext(dctx, 1); 185030f984aSJacob Faibussowitsch PetscValidStreamType(type, 2); 1860e6b6b59SJacob Faibussowitsch // only need to do complex swapping if the object has already been setup 187030f984aSJacob Faibussowitsch if (dctx->setup && (dctx->streamType != type)) { 188030f984aSJacob Faibussowitsch dctx->setup = PETSC_FALSE; 1896a4a1270SPierre Jolivet PetscCall(PetscLogEventBegin(DCONTEXT_ChangeStream, dctx, nullptr, nullptr, nullptr)); 1900e6b6b59SJacob Faibussowitsch PetscUseTypeMethod(dctx, changestreamtype, type); 1916a4a1270SPierre Jolivet PetscCall(PetscLogEventEnd(DCONTEXT_ChangeStream, dctx, nullptr, nullptr, nullptr)); 192030f984aSJacob Faibussowitsch } 193030f984aSJacob Faibussowitsch dctx->streamType = type; 1943ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 195030f984aSJacob Faibussowitsch } 196030f984aSJacob Faibussowitsch 197030f984aSJacob Faibussowitsch /*@C 1980e6b6b59SJacob Faibussowitsch PetscDeviceContextGetStreamType - Get the implementation type of the underlying stream for a 1990e6b6b59SJacob Faibussowitsch `PetscDeviceContext` 200030f984aSJacob Faibussowitsch 2010e6b6b59SJacob Faibussowitsch Not Collective 202030f984aSJacob Faibussowitsch 20301d2d390SJose E. Roman Input Parameter: 204811af0c4SBarry Smith . dctx - The `PetscDeviceContext` 205030f984aSJacob Faibussowitsch 206030f984aSJacob Faibussowitsch Output Parameter: 207811af0c4SBarry Smith . type - The `PetscStreamType` 208030f984aSJacob Faibussowitsch 2092fe279fdSBarry Smith Level: beginner 2102fe279fdSBarry Smith 2112fe279fdSBarry Smith Note: 2120e6b6b59SJacob Faibussowitsch See `PetscStreamType` in `include/petscdevicetypes.h` for more information on the available 2130e6b6b59SJacob Faibussowitsch types and their interactions 214030f984aSJacob Faibussowitsch 2150e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextSetStreamType()`, `PetscDeviceContextCreate()`, 2160e6b6b59SJacob Faibussowitsch `PetscDeviceContextSetFromOptions()` 217030f984aSJacob Faibussowitsch @*/ 218d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextGetStreamType(PetscDeviceContext dctx, PetscStreamType *type) 219d71ae5a4SJacob Faibussowitsch { 220030f984aSJacob Faibussowitsch PetscFunctionBegin; 2210e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx)); 2224f572ea9SToby Isaac PetscAssertPointer(type, 2); 223030f984aSJacob Faibussowitsch *type = dctx->streamType; 2243ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 225030f984aSJacob Faibussowitsch } 226030f984aSJacob Faibussowitsch 2270e6b6b59SJacob Faibussowitsch /* 2280e6b6b59SJacob Faibussowitsch Actual function to set the device. 229030f984aSJacob Faibussowitsch 2300e6b6b59SJacob Faibussowitsch 1. Repeatedly destroying and recreating internal data structures (like streams and events) 2310e6b6b59SJacob Faibussowitsch for recycled PetscDeviceContexts is not free. If done often, it does add up. 2320e6b6b59SJacob Faibussowitsch 2. The vast majority of PetscDeviceContexts are created by PETSc either as children or 23335cb6cd3SPierre Jolivet default contexts. The default contexts *never* change type, and the children are extremely 2340e6b6b59SJacob Faibussowitsch unlikely to (chances are if you fork once, you will fork again very soon). 2350e6b6b59SJacob Faibussowitsch 3. The only time this calculus changes is if the user themselves sets the device type. In 2360e6b6b59SJacob Faibussowitsch this case we do not know what the user has changed, so must always wipe the slate clean. 2370e6b6b59SJacob Faibussowitsch 2380e6b6b59SJacob Faibussowitsch Thus we need to keep track whether the user explicitly sets the device contexts device. 2390e6b6b59SJacob Faibussowitsch */ 240d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDeviceContextSetDevice_Private(PetscDeviceContext dctx, PetscDevice device, PetscBool user_set) 241d71ae5a4SJacob Faibussowitsch { 2420e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 2430e6b6b59SJacob Faibussowitsch // do not use getoptionalnullcontext here since we do not want the user to change its device 2440e6b6b59SJacob Faibussowitsch PetscValidDeviceContext(dctx, 1); 2450e6b6b59SJacob Faibussowitsch PetscValidDevice(device, 2); 2463ba16761SJacob Faibussowitsch if (dctx->device && (dctx->device->id == device->id)) PetscFunctionReturn(PETSC_SUCCESS); 2476a4a1270SPierre Jolivet PetscCall(PetscLogEventBegin(DCONTEXT_SetDevice, dctx, nullptr, nullptr, nullptr)); 2482126a61dSJacob Faibussowitsch PetscTryTypeMethod(dctx, destroy); 2490e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceDestroy(&dctx->device)); 2500e6b6b59SJacob Faibussowitsch PetscCall(PetscMemzero(dctx->ops, sizeof(*dctx->ops))); 2512126a61dSJacob Faibussowitsch PetscCall(PetscDeviceReference_Internal(device)); 2522126a61dSJacob Faibussowitsch // set it before calling the method 2532126a61dSJacob Faibussowitsch dctx->device = device; 2540e6b6b59SJacob Faibussowitsch PetscCall((*device->ops->createcontext)(dctx)); 2556a4a1270SPierre Jolivet PetscCall(PetscLogEventEnd(DCONTEXT_SetDevice, dctx, nullptr, nullptr, nullptr)); 2560e6b6b59SJacob Faibussowitsch dctx->setup = PETSC_FALSE; 2570e6b6b59SJacob Faibussowitsch dctx->usersetdevice = user_set; 2583ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2590e6b6b59SJacob Faibussowitsch } 2600e6b6b59SJacob Faibussowitsch 261d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetDefaultDeviceForType_Internal(PetscDeviceContext dctx, PetscDeviceType type) 262d71ae5a4SJacob Faibussowitsch { 2630e6b6b59SJacob Faibussowitsch PetscDevice device; 2640e6b6b59SJacob Faibussowitsch 2650e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 2660e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceGetDefaultForType_Internal(type, &device)); 2670e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextSetDevice_Private(dctx, device, PETSC_FALSE)); 2683ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2690e6b6b59SJacob Faibussowitsch } 2700e6b6b59SJacob Faibussowitsch 2710e6b6b59SJacob Faibussowitsch /*@C 2720e6b6b59SJacob Faibussowitsch PetscDeviceContextSetDevice - Set the underlying `PetscDevice` for a `PetscDeviceContext` 2730e6b6b59SJacob Faibussowitsch 2740e6b6b59SJacob Faibussowitsch Not Collective 275030f984aSJacob Faibussowitsch 27601d2d390SJose E. Roman Input Parameters: 277811af0c4SBarry Smith + dctx - The `PetscDeviceContext` 278811af0c4SBarry Smith - device - The `PetscDevice` 279030f984aSJacob Faibussowitsch 2802fe279fdSBarry Smith Level: intermediate 2812fe279fdSBarry Smith 282030f984aSJacob Faibussowitsch Notes: 2830e6b6b59SJacob Faibussowitsch This routine is effectively `PetscDeviceContext`'s "set-type" (so every `PetscDeviceContext` must 284da81f932SPierre Jolivet also have an attached `PetscDevice`). Unlike the usual set-type semantics, it is not strictly 2850e6b6b59SJacob Faibussowitsch necessary to set a contexts device to enable usage, any created `PetscDeviceContext`s will 2860e6b6b59SJacob Faibussowitsch always come equipped with the "default" device. 287030f984aSJacob Faibussowitsch 2880e6b6b59SJacob Faibussowitsch This routine is a no-op if `device` is already attached to `dctx`. 289a4af0ceeSJacob Faibussowitsch 2900e6b6b59SJacob Faibussowitsch This routine may (but is very unlikely to) initialize the backend device and may incur 2910e6b6b59SJacob Faibussowitsch synchronization. 2925181c4f9SJacob Faibussowitsch 2930e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceCreate()`, `PetscDeviceConfigure()`, `PetscDeviceContextGetDevice()`, 2940e6b6b59SJacob Faibussowitsch `PetscDeviceContextGetDeviceType()` 295030f984aSJacob Faibussowitsch @*/ 296d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetDevice(PetscDeviceContext dctx, PetscDevice device) 297d71ae5a4SJacob Faibussowitsch { 298030f984aSJacob Faibussowitsch PetscFunctionBegin; 2990e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextSetDevice_Private(dctx, device, PETSC_TRUE)); 3003ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 301030f984aSJacob Faibussowitsch } 302030f984aSJacob Faibussowitsch 303030f984aSJacob Faibussowitsch /*@C 304811af0c4SBarry Smith PetscDeviceContextGetDevice - Get the underlying `PetscDevice` for a `PetscDeviceContext` 305030f984aSJacob Faibussowitsch 3060e6b6b59SJacob Faibussowitsch Not Collective 307030f984aSJacob Faibussowitsch 308030f984aSJacob Faibussowitsch Input Parameter: 309811af0c4SBarry Smith . dctx - the `PetscDeviceContext` 310030f984aSJacob Faibussowitsch 311030f984aSJacob Faibussowitsch Output Parameter: 312811af0c4SBarry Smith . device - The `PetscDevice` 313030f984aSJacob Faibussowitsch 314a375dbeeSPatrick Sanan Level: intermediate 315a375dbeeSPatrick Sanan 3162fe279fdSBarry Smith Note: 3172fe279fdSBarry Smith This is a borrowed reference, the user should not destroy `device`. 3182fe279fdSBarry Smith 3190e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextSetDevice()`, `PetscDevice`, `PetscDeviceContextGetDeviceType()` 320030f984aSJacob Faibussowitsch @*/ 321d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextGetDevice(PetscDeviceContext dctx, PetscDevice *device) 322d71ae5a4SJacob Faibussowitsch { 323030f984aSJacob Faibussowitsch PetscFunctionBegin; 3240e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx)); 3254f572ea9SToby Isaac PetscAssertPointer(device, 2); 3260e6b6b59SJacob Faibussowitsch PetscAssert(dctx->device, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "PetscDeviceContext %" PetscInt64_FMT " has no attached PetscDevice to get", PetscObjectCast(dctx)->id); 327030f984aSJacob Faibussowitsch *device = dctx->device; 3283ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 329030f984aSJacob Faibussowitsch } 330030f984aSJacob Faibussowitsch 331030f984aSJacob Faibussowitsch /*@C 3320e6b6b59SJacob Faibussowitsch PetscDeviceContextGetDeviceType - Get the `PetscDeviceType` for a `PetscDeviceContext` 3330e6b6b59SJacob Faibussowitsch 3340e6b6b59SJacob Faibussowitsch Not Collective 3350e6b6b59SJacob Faibussowitsch 3360e6b6b59SJacob Faibussowitsch Input Parameter: 3370e6b6b59SJacob Faibussowitsch . dctx - The `PetscDeviceContext` 3380e6b6b59SJacob Faibussowitsch 3390e6b6b59SJacob Faibussowitsch Output Parameter: 3400e6b6b59SJacob Faibussowitsch . type - The `PetscDeviceType` 3410e6b6b59SJacob Faibussowitsch 3422fe279fdSBarry Smith Level: beginner 3432fe279fdSBarry Smith 3442fe279fdSBarry Smith Note: 3450e6b6b59SJacob Faibussowitsch This routine is a convenience shorthand for `PetscDeviceContextGetDevice()` -> 3460e6b6b59SJacob Faibussowitsch `PetscDeviceGetType()`. 3470e6b6b59SJacob Faibussowitsch 3480e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceType`, `PetscDeviceContextGetDevice()`, `PetscDeviceGetType()`, `PetscDevice` 3490e6b6b59SJacob Faibussowitsch @*/ 350d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextGetDeviceType(PetscDeviceContext dctx, PetscDeviceType *type) 351d71ae5a4SJacob Faibussowitsch { 3520e6b6b59SJacob Faibussowitsch PetscDevice device = nullptr; 3530e6b6b59SJacob Faibussowitsch 3540e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 3550e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx)); 3564f572ea9SToby Isaac PetscAssertPointer(type, 2); 3570e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetDevice(dctx, &device)); 3580e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceGetType(device, type)); 3593ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3600e6b6b59SJacob Faibussowitsch } 3610e6b6b59SJacob Faibussowitsch 3620e6b6b59SJacob Faibussowitsch /*@C 363811af0c4SBarry Smith PetscDeviceContextSetUp - Prepares a `PetscDeviceContext` for use 364030f984aSJacob Faibussowitsch 3650e6b6b59SJacob Faibussowitsch Not Collective 366030f984aSJacob Faibussowitsch 36701d2d390SJose E. Roman Input Parameter: 368811af0c4SBarry Smith . dctx - The `PetscDeviceContext` 369030f984aSJacob Faibussowitsch 3702fe279fdSBarry Smith Level: beginner 3712fe279fdSBarry Smith 372aec76313SJacob Faibussowitsch Developer Notes: 3730e6b6b59SJacob Faibussowitsch This routine is usually the stage where a `PetscDeviceContext` acquires device-side data 3740e6b6b59SJacob Faibussowitsch structures such as streams, events, and (possibly) handles. 375030f984aSJacob Faibussowitsch 3760e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextSetDevice()`, 3770e6b6b59SJacob Faibussowitsch `PetscDeviceContextDestroy()`, `PetscDeviceContextSetFromOptions()` 378030f984aSJacob Faibussowitsch @*/ 379d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetUp(PetscDeviceContext dctx) 380d71ae5a4SJacob Faibussowitsch { 381030f984aSJacob Faibussowitsch PetscFunctionBegin; 3820e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx)); 3833ba16761SJacob Faibussowitsch if (dctx->setup) PetscFunctionReturn(PETSC_SUCCESS); 3840e6b6b59SJacob Faibussowitsch if (!dctx->device) { 3850e6b6b59SJacob Faibussowitsch const auto default_dtype = PETSC_DEVICE_DEFAULT(); 3860e6b6b59SJacob Faibussowitsch 3870e6b6b59SJacob Faibussowitsch PetscCall(PetscInfo(dctx, "PetscDeviceContext %" PetscInt64_FMT " did not have an explicitly attached PetscDevice, using default with type %s\n", PetscObjectCast(dctx)->id, PetscDeviceTypes[default_dtype])); 3880e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextSetDefaultDeviceForType_Internal(dctx, default_dtype)); 3890e6b6b59SJacob Faibussowitsch } 3906a4a1270SPierre Jolivet PetscCall(PetscLogEventBegin(DCONTEXT_SetUp, dctx, nullptr, nullptr, nullptr)); 391dbbe0bcdSBarry Smith PetscUseTypeMethod(dctx, setup); 3926a4a1270SPierre Jolivet PetscCall(PetscLogEventEnd(DCONTEXT_SetUp, dctx, nullptr, nullptr, nullptr)); 393030f984aSJacob Faibussowitsch dctx->setup = PETSC_TRUE; 3943ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 395030f984aSJacob Faibussowitsch } 396030f984aSJacob Faibussowitsch 397d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDeviceContextDuplicate_Private(PetscDeviceContext dctx, PetscStreamType stype, PetscDeviceContext *dctxdup) 398d71ae5a4SJacob Faibussowitsch { 3990e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 4006a4a1270SPierre Jolivet PetscCall(PetscLogEventBegin(DCONTEXT_Duplicate, dctx, nullptr, nullptr, nullptr)); 4010e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextCreate(dctxdup)); 4020e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextSetStreamType(*dctxdup, stype)); 4030e6b6b59SJacob Faibussowitsch if (const auto device = dctx->device) PetscCall(PetscDeviceContextSetDevice_Private(*dctxdup, device, dctx->usersetdevice)); 4040e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextSetUp(*dctxdup)); 4056a4a1270SPierre Jolivet PetscCall(PetscLogEventEnd(DCONTEXT_Duplicate, dctx, nullptr, nullptr, nullptr)); 4063ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 4070e6b6b59SJacob Faibussowitsch } 4080e6b6b59SJacob Faibussowitsch 40910450e9eSJacob Faibussowitsch // PetscClangLinter pragma disable: -fdoc-section-header-unknown 410030f984aSJacob Faibussowitsch /*@C 411811af0c4SBarry Smith PetscDeviceContextDuplicate - Duplicates a `PetscDeviceContext` object 412030f984aSJacob Faibussowitsch 4130e6b6b59SJacob Faibussowitsch Not Collective 414030f984aSJacob Faibussowitsch 415030f984aSJacob Faibussowitsch Input Parameter: 416811af0c4SBarry Smith . dctx - The `PetscDeviceContext` to duplicate 417030f984aSJacob Faibussowitsch 4186aad120cSJose E. Roman Output Parameter: 419811af0c4SBarry Smith . dctxdup - The duplicated `PetscDeviceContext` 420030f984aSJacob Faibussowitsch 4212fe279fdSBarry Smith Level: beginner 4222fe279fdSBarry Smith 4230e6b6b59SJacob Faibussowitsch Notes: 4240e6b6b59SJacob Faibussowitsch This is a shorthand method for creating a `PetscDeviceContext` with the exact same settings as 4250e6b6b59SJacob Faibussowitsch another. Note however that `dctxdup` does not share any of the underlying data with `dctx`, 4260e6b6b59SJacob Faibussowitsch (including its current stream-state) they are completely separate objects. 4270e6b6b59SJacob Faibussowitsch 4280e6b6b59SJacob Faibussowitsch There is no implied ordering between `dctx` or `dctxdup`. 4290e6b6b59SJacob Faibussowitsch 4300e6b6b59SJacob Faibussowitsch DAG representation: 4310e6b6b59SJacob Faibussowitsch .vb 4320e6b6b59SJacob Faibussowitsch time -> 4330e6b6b59SJacob Faibussowitsch 4340e6b6b59SJacob Faibussowitsch -> dctx - |= CALL =| - dctx ----> 4350e6b6b59SJacob Faibussowitsch - dctxdup -> 4360e6b6b59SJacob Faibussowitsch .ve 437030f984aSJacob Faibussowitsch 4380e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextSetDevice()`, 4390e6b6b59SJacob Faibussowitsch `PetscDeviceContextSetStreamType()` 440030f984aSJacob Faibussowitsch @*/ 441d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextDuplicate(PetscDeviceContext dctx, PetscDeviceContext *dctxdup) 442d71ae5a4SJacob Faibussowitsch { 4430e6b6b59SJacob Faibussowitsch auto stype = PETSC_STREAM_DEFAULT_BLOCKING; 444030f984aSJacob Faibussowitsch 445030f984aSJacob Faibussowitsch PetscFunctionBegin; 4460e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx)); 4474f572ea9SToby Isaac PetscAssertPointer(dctxdup, 2); 4480e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetStreamType(dctx, &stype)); 4490e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextDuplicate_Private(dctx, stype, dctxdup)); 4503ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 451030f984aSJacob Faibussowitsch } 452030f984aSJacob Faibussowitsch 453030f984aSJacob Faibussowitsch /*@C 454811af0c4SBarry Smith PetscDeviceContextQueryIdle - Returns whether or not a `PetscDeviceContext` is idle 455030f984aSJacob Faibussowitsch 4560e6b6b59SJacob Faibussowitsch Not Collective 457030f984aSJacob Faibussowitsch 458030f984aSJacob Faibussowitsch Input Parameter: 4590e6b6b59SJacob Faibussowitsch . dctx - The `PetscDeviceContext` 460030f984aSJacob Faibussowitsch 461030f984aSJacob Faibussowitsch Output Parameter: 4620e6b6b59SJacob Faibussowitsch . idle - `PETSC_TRUE` if `dctx` has NO work, `PETSC_FALSE` if it has work 463030f984aSJacob Faibussowitsch 4642fe279fdSBarry Smith Level: intermediate 4652fe279fdSBarry Smith 466811af0c4SBarry Smith Note: 467ef657721SJacob Faibussowitsch This routine only refers a singular context and does NOT take any of its children into 4680e6b6b59SJacob Faibussowitsch account. That is, if `dctx` is idle but has dependents who do have work this routine still 469811af0c4SBarry Smith returns `PETSC_TRUE`. 470030f984aSJacob Faibussowitsch 471db781477SPatrick Sanan .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextWaitForContext()`, `PetscDeviceContextFork()` 472030f984aSJacob Faibussowitsch @*/ 473d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextQueryIdle(PetscDeviceContext dctx, PetscBool *idle) 474d71ae5a4SJacob Faibussowitsch { 475030f984aSJacob Faibussowitsch PetscFunctionBegin; 4760e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx)); 4774f572ea9SToby Isaac PetscAssertPointer(idle, 2); 4786a4a1270SPierre Jolivet PetscCall(PetscLogEventBegin(DCONTEXT_QueryIdle, dctx, nullptr, nullptr, nullptr)); 479dbbe0bcdSBarry Smith PetscUseTypeMethod(dctx, query, idle); 4806a4a1270SPierre Jolivet PetscCall(PetscLogEventEnd(DCONTEXT_QueryIdle, dctx, nullptr, nullptr, nullptr)); 4810e6b6b59SJacob Faibussowitsch PetscCall(PetscInfo(dctx, "PetscDeviceContext ('%s', id %" PetscInt64_FMT ") %s idle\n", PetscObjectCast(dctx)->name ? PetscObjectCast(dctx)->name : "unnamed", PetscObjectCast(dctx)->id, *idle ? "was" : "was not")); 4823ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 483030f984aSJacob Faibussowitsch } 484030f984aSJacob Faibussowitsch 48510450e9eSJacob Faibussowitsch // PetscClangLinter pragma disable: -fdoc-section-header-unknown 486030f984aSJacob Faibussowitsch /*@C 487030f984aSJacob Faibussowitsch PetscDeviceContextWaitForContext - Make one context wait for another context to finish 488030f984aSJacob Faibussowitsch 4890e6b6b59SJacob Faibussowitsch Not Collective 490030f984aSJacob Faibussowitsch 491030f984aSJacob Faibussowitsch Input Parameters: 492811af0c4SBarry Smith + dctxa - The `PetscDeviceContext` object that is waiting 493811af0c4SBarry Smith - dctxb - The `PetscDeviceContext` object that is being waited on 494030f984aSJacob Faibussowitsch 4952fe279fdSBarry Smith Level: beginner 4962fe279fdSBarry Smith 497030f984aSJacob Faibussowitsch Notes: 4980e6b6b59SJacob Faibussowitsch Serializes two `PetscDeviceContext`s. Serialization is performed asynchronously; the host 4990e6b6b59SJacob Faibussowitsch does not wait for the serialization to actually occur. 500811af0c4SBarry Smith 5010e6b6b59SJacob Faibussowitsch This routine uses only the state of `dctxb` at the moment this routine was called, so any 5020e6b6b59SJacob Faibussowitsch future work queued will not affect `dctxa`. It is safe to pass the same context to both 5030e6b6b59SJacob Faibussowitsch arguments (in which case this routine does nothing). 5040e6b6b59SJacob Faibussowitsch 5050e6b6b59SJacob Faibussowitsch DAG representation: 5060e6b6b59SJacob Faibussowitsch .vb 5070e6b6b59SJacob Faibussowitsch time -> 5080e6b6b59SJacob Faibussowitsch 5090e6b6b59SJacob Faibussowitsch -> dctxa ---/- |= CALL =| - dctxa -> 5100e6b6b59SJacob Faibussowitsch / 5110e6b6b59SJacob Faibussowitsch -> dctxb -/------------------------> 5120e6b6b59SJacob Faibussowitsch .ve 513030f984aSJacob Faibussowitsch 5140e6b6b59SJacob Faibussowitsch .N ASYNC_API 5150e6b6b59SJacob Faibussowitsch 516db781477SPatrick Sanan .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextQueryIdle()`, `PetscDeviceContextJoin()` 517030f984aSJacob Faibussowitsch @*/ 518d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextWaitForContext(PetscDeviceContext dctxa, PetscDeviceContext dctxb) 519d71ae5a4SJacob Faibussowitsch { 520*dcf958e2SJacob Faibussowitsch PetscObjectId bid; 5210e6b6b59SJacob Faibussowitsch 522030f984aSJacob Faibussowitsch PetscFunctionBegin; 5230e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctxa)); 5240e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctxb)); 525030f984aSJacob Faibussowitsch PetscCheckCompatibleDeviceContexts(dctxa, 1, dctxb, 2); 5263ba16761SJacob Faibussowitsch if (dctxa == dctxb) PetscFunctionReturn(PETSC_SUCCESS); 527*dcf958e2SJacob Faibussowitsch bid = PetscObjectCast(dctxb)->id; 5286a4a1270SPierre Jolivet PetscCall(PetscLogEventBegin(DCONTEXT_WaitForCtx, dctxa, dctxb, nullptr, nullptr)); 529dbbe0bcdSBarry Smith PetscUseTypeMethod(dctxa, waitforcontext, dctxb); 530*dcf958e2SJacob Faibussowitsch PetscCallCXX(CxxDataCast(dctxa)->upstream()[bid] = CxxDataCast(dctxb)->weak_snapshot()); 5316a4a1270SPierre Jolivet PetscCall(PetscLogEventEnd(DCONTEXT_WaitForCtx, dctxa, dctxb, nullptr, nullptr)); 532*dcf958e2SJacob Faibussowitsch PetscCall(PetscInfo(dctxa, "dctx %" PetscInt64_FMT " waiting on dctx %" PetscInt64_FMT "\n", PetscObjectCast(dctxa)->id, bid)); 533*dcf958e2SJacob Faibussowitsch PetscCall(PetscObjectStateIncrease(PetscObjectCast(dctxa))); 5343ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 535030f984aSJacob Faibussowitsch } 536030f984aSJacob Faibussowitsch 53710450e9eSJacob Faibussowitsch // PetscClangLinter pragma disable: -fdoc-section-header-unknown 5380e6b6b59SJacob Faibussowitsch /*@C 5390e6b6b59SJacob Faibussowitsch PetscDeviceContextForkWithStreamType - Create a set of dependent child contexts from a parent 5400e6b6b59SJacob Faibussowitsch context with a prescribed `PetscStreamType` 5410e6b6b59SJacob Faibussowitsch 5420e6b6b59SJacob Faibussowitsch Not Collective, Asynchronous 5430e6b6b59SJacob Faibussowitsch 5440e6b6b59SJacob Faibussowitsch Input Parameters: 5450e6b6b59SJacob Faibussowitsch + dctx - The parent `PetscDeviceContext` 5460e6b6b59SJacob Faibussowitsch . stype - The prescribed `PetscStreamType` 5470e6b6b59SJacob Faibussowitsch - n - The number of children to create 5480e6b6b59SJacob Faibussowitsch 5490e6b6b59SJacob Faibussowitsch Output Parameter: 5500e6b6b59SJacob Faibussowitsch . dsub - The created child context(s) 5510e6b6b59SJacob Faibussowitsch 5522fe279fdSBarry Smith Level: intermediate 5532fe279fdSBarry Smith 5540e6b6b59SJacob Faibussowitsch Notes: 5550e6b6b59SJacob Faibussowitsch This routine creates `n` edges of a DAG from a source node which are causally dependent on the 5560e6b6b59SJacob Faibussowitsch source node. This causal dependency is established as-if by calling 5570e6b6b59SJacob Faibussowitsch `PetscDeviceContextWaitForContext()` on every child. 5580e6b6b59SJacob Faibussowitsch 5590e6b6b59SJacob Faibussowitsch `dsub` is allocated by this routine and has its lifetime bounded by `dctx`. That is, `dctx` 5600e6b6b59SJacob Faibussowitsch expects to free `dsub` (via `PetscDeviceContextJoin()`) before it itself is destroyed. 5610e6b6b59SJacob Faibussowitsch 5620e6b6b59SJacob Faibussowitsch This routine only accounts for work queued on `dctx` up until calling this routine, any 5630e6b6b59SJacob Faibussowitsch subsequent work enqueued on `dctx` has no effect on `dsub`. 5640e6b6b59SJacob Faibussowitsch 5650e6b6b59SJacob Faibussowitsch The `PetscStreamType` of `dctx` does not have to equal `stype`. In fact, it is often the case 5660e6b6b59SJacob Faibussowitsch that they are different. This is useful in cases where a routine can locally exploit stream 5670e6b6b59SJacob Faibussowitsch parallelism without needing to worry about what stream type the incoming `PetscDeviceContext` 5680e6b6b59SJacob Faibussowitsch carries. 5690e6b6b59SJacob Faibussowitsch 5700e6b6b59SJacob Faibussowitsch DAG representation: 5710e6b6b59SJacob Faibussowitsch .vb 5720e6b6b59SJacob Faibussowitsch time -> 5730e6b6b59SJacob Faibussowitsch 5740e6b6b59SJacob Faibussowitsch -> dctx - |= CALL =| -\----> dctx ------> 5750e6b6b59SJacob Faibussowitsch \---> dsub[0] ---> 5760e6b6b59SJacob Faibussowitsch \--> ... -------> 5770e6b6b59SJacob Faibussowitsch \-> dsub[n-1] -> 5780e6b6b59SJacob Faibussowitsch .ve 5790e6b6b59SJacob Faibussowitsch 5800e6b6b59SJacob Faibussowitsch .N ASYNC_API 5810e6b6b59SJacob Faibussowitsch 5820e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextJoin()`, `PetscDeviceContextSynchronize()`, 5830e6b6b59SJacob Faibussowitsch `PetscDeviceContextQueryIdle()`, `PetscDeviceContextWaitForContext()` 5840e6b6b59SJacob Faibussowitsch @*/ 585d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextForkWithStreamType(PetscDeviceContext dctx, PetscStreamType stype, PetscInt n, PetscDeviceContext **dsub) 586d71ae5a4SJacob Faibussowitsch { 5870e6b6b59SJacob Faibussowitsch // debugging only 5880e6b6b59SJacob Faibussowitsch std::string idList; 5890e6b6b59SJacob Faibussowitsch auto ninput = n; 5900e6b6b59SJacob Faibussowitsch 5910e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 5920e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx)); 5930e6b6b59SJacob Faibussowitsch PetscAssert(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of contexts requested %" PetscInt_FMT " < 0", n); 5944f572ea9SToby Isaac PetscAssertPointer(dsub, 4); 5950e6b6b59SJacob Faibussowitsch *dsub = nullptr; 5960e6b6b59SJacob Faibussowitsch /* reserve 4 chars per id, 2 for number and 2 for ', ' separator */ 5970e6b6b59SJacob Faibussowitsch if (PetscDefined(USE_DEBUG_AND_INFO)) PetscCallCXX(idList.reserve(4 * n)); 5986a4a1270SPierre Jolivet PetscCall(PetscLogEventBegin(DCONTEXT_Fork, dctx, nullptr, nullptr, nullptr)); 5990e6b6b59SJacob Faibussowitsch /* update child totals */ 6000e6b6b59SJacob Faibussowitsch dctx->numChildren += n; 6010e6b6b59SJacob Faibussowitsch /* now to find out if we have room */ 6020e6b6b59SJacob Faibussowitsch if (dctx->numChildren > dctx->maxNumChildren) { 6030e6b6b59SJacob Faibussowitsch const auto numChildren = dctx->numChildren; 6040e6b6b59SJacob Faibussowitsch auto &maxNumChildren = dctx->maxNumChildren; 6050e6b6b59SJacob Faibussowitsch auto numAllocated = numChildren; 6060e6b6b59SJacob Faibussowitsch 6070e6b6b59SJacob Faibussowitsch /* no room, either from having too many kids or not having any */ 6080e6b6b59SJacob Faibussowitsch if (auto &childIDs = dctx->childIDs) { 6090e6b6b59SJacob Faibussowitsch // the difference is backwards because we have not updated maxNumChildren yet 6100e6b6b59SJacob Faibussowitsch numAllocated -= maxNumChildren; 6110e6b6b59SJacob Faibussowitsch /* have existing children, must reallocate them */ 6120e6b6b59SJacob Faibussowitsch PetscCall(PetscRealloc(numChildren * sizeof(*childIDs), &childIDs)); 6130e6b6b59SJacob Faibussowitsch /* clear the extra memory since realloc doesn't do it for us */ 6140e6b6b59SJacob Faibussowitsch PetscCall(PetscArrayzero(std::next(childIDs, maxNumChildren), numAllocated)); 6150e6b6b59SJacob Faibussowitsch } else { 6160e6b6b59SJacob Faibussowitsch /* have no children */ 6170e6b6b59SJacob Faibussowitsch PetscCall(PetscCalloc1(numChildren, &childIDs)); 6180e6b6b59SJacob Faibussowitsch } 6190e6b6b59SJacob Faibussowitsch /* update total number of children */ 6200e6b6b59SJacob Faibussowitsch maxNumChildren = numChildren; 6210e6b6b59SJacob Faibussowitsch } 6220e6b6b59SJacob Faibussowitsch PetscCall(PetscMalloc1(n, dsub)); 6230e6b6b59SJacob Faibussowitsch for (PetscInt i = 0; ninput && (i < dctx->numChildren); ++i) { 6240e6b6b59SJacob Faibussowitsch auto &childID = dctx->childIDs[i]; 6250e6b6b59SJacob Faibussowitsch /* empty child slot */ 6260e6b6b59SJacob Faibussowitsch if (!childID) { 6270e6b6b59SJacob Faibussowitsch auto &childctx = (*dsub)[i]; 6280e6b6b59SJacob Faibussowitsch 6290e6b6b59SJacob Faibussowitsch /* create the child context in the image of its parent */ 6300e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextDuplicate_Private(dctx, stype, &childctx)); 6310e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextWaitForContext(childctx, dctx)); 6320e6b6b59SJacob Faibussowitsch /* register the child with its parent */ 6330e6b6b59SJacob Faibussowitsch PetscCall(PetscObjectGetId(PetscObjectCast(childctx), &childID)); 6340e6b6b59SJacob Faibussowitsch if (PetscDefined(USE_DEBUG_AND_INFO)) { 6350e6b6b59SJacob Faibussowitsch PetscCallCXX(idList += std::to_string(childID)); 6360e6b6b59SJacob Faibussowitsch if (ninput != 1) PetscCallCXX(idList += ", "); 6370e6b6b59SJacob Faibussowitsch } 6380e6b6b59SJacob Faibussowitsch --ninput; 6390e6b6b59SJacob Faibussowitsch } 6400e6b6b59SJacob Faibussowitsch } 6416a4a1270SPierre Jolivet PetscCall(PetscLogEventEnd(DCONTEXT_Fork, dctx, nullptr, nullptr, nullptr)); 6420e6b6b59SJacob Faibussowitsch PetscCall(PetscDebugInfo(dctx, "Forked %" PetscInt_FMT " children from parent %" PetscInt64_FMT " with IDs: %s\n", n, PetscObjectCast(dctx)->id, idList.c_str())); 6433ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 6440e6b6b59SJacob Faibussowitsch } 6450e6b6b59SJacob Faibussowitsch 646030f984aSJacob Faibussowitsch /*@C 647030f984aSJacob Faibussowitsch PetscDeviceContextFork - Create a set of dependent child contexts from a parent context 648030f984aSJacob Faibussowitsch 649030f984aSJacob Faibussowitsch Not Collective, Asynchronous 650030f984aSJacob Faibussowitsch 651030f984aSJacob Faibussowitsch Input Parameters: 652811af0c4SBarry Smith + dctx - The parent `PetscDeviceContext` 653030f984aSJacob Faibussowitsch - n - The number of children to create 654030f984aSJacob Faibussowitsch 655030f984aSJacob Faibussowitsch Output Parameter: 656030f984aSJacob Faibussowitsch . dsub - The created child context(s) 657030f984aSJacob Faibussowitsch 6582fe279fdSBarry Smith Level: beginner 6592fe279fdSBarry Smith 660030f984aSJacob Faibussowitsch Notes: 6610e6b6b59SJacob Faibussowitsch Behaves identically to `PetscDeviceContextForkWithStreamType()` except that the prescribed 6620e6b6b59SJacob Faibussowitsch `PetscStreamType` is taken from `dctx`. In effect this routine is shorthand for\: 663030f984aSJacob Faibussowitsch 664030f984aSJacob Faibussowitsch .vb 6650e6b6b59SJacob Faibussowitsch PetscStreamType stype; 666030f984aSJacob Faibussowitsch 6670e6b6b59SJacob Faibussowitsch PetscDeviceContextGetStreamType(dctx, &stype); 6680e6b6b59SJacob Faibussowitsch PetscDeviceContextForkWithStreamType(dctx, stype, ...); 669030f984aSJacob Faibussowitsch .ve 670030f984aSJacob Faibussowitsch 6710e6b6b59SJacob Faibussowitsch .N ASYNC_API 6720e6b6b59SJacob Faibussowitsch 6730e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextForkWithStreamType()`, `PetscDeviceContextJoin()`, 6740e6b6b59SJacob Faibussowitsch `PetscDeviceContextSynchronize()`, `PetscDeviceContextQueryIdle()` 675030f984aSJacob Faibussowitsch @*/ 676d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextFork(PetscDeviceContext dctx, PetscInt n, PetscDeviceContext **dsub) 677d71ae5a4SJacob Faibussowitsch { 6780e6b6b59SJacob Faibussowitsch auto stype = PETSC_STREAM_DEFAULT_BLOCKING; 679030f984aSJacob Faibussowitsch 680030f984aSJacob Faibussowitsch PetscFunctionBegin; 6810e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx)); 6820e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetStreamType(dctx, &stype)); 6830e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextForkWithStreamType(dctx, stype, n, dsub)); 6843ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 685030f984aSJacob Faibussowitsch } 686030f984aSJacob Faibussowitsch 68710450e9eSJacob Faibussowitsch // PetscClangLinter pragma disable: -fdoc-section-header-unknown 688030f984aSJacob Faibussowitsch /*@C 6895181c4f9SJacob Faibussowitsch PetscDeviceContextJoin - Converge a set of child contexts 690030f984aSJacob Faibussowitsch 691030f984aSJacob Faibussowitsch Not Collective, Asynchronous 692030f984aSJacob Faibussowitsch 693030f984aSJacob Faibussowitsch Input Parameters: 694811af0c4SBarry Smith + dctx - A `PetscDeviceContext` to converge on 695030f984aSJacob Faibussowitsch . n - The number of sub contexts to converge 696030f984aSJacob Faibussowitsch . joinMode - The type of join to perform 697030f984aSJacob Faibussowitsch - dsub - The sub contexts to converge 698030f984aSJacob Faibussowitsch 6992fe279fdSBarry Smith Level: beginner 7002fe279fdSBarry Smith 701030f984aSJacob Faibussowitsch Notes: 7020e6b6b59SJacob Faibussowitsch If `PetscDeviceContextFork()` creates `n` edges from a source node which all depend on the source 7030e6b6b59SJacob Faibussowitsch node, then this routine is the exact mirror. That is, it creates a node (represented in `dctx`) 70435cb6cd3SPierre Jolivet which receives `n` edges (and optionally destroys them) which is dependent on the completion 7050e6b6b59SJacob Faibussowitsch of all incoming edges. 706030f984aSJacob Faibussowitsch 7070e6b6b59SJacob Faibussowitsch If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_DESTROY`. All contexts in `dsub` will be 7080e6b6b59SJacob Faibussowitsch destroyed by this routine. Thus all sub contexts must have been created with the `dctx` 7090e6b6b59SJacob Faibussowitsch passed to this routine. 710030f984aSJacob Faibussowitsch 7110e6b6b59SJacob Faibussowitsch If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_SYNC`. All sub contexts will additionally wait on 7120e6b6b59SJacob Faibussowitsch `dctx` after converging. This has the effect of "synchronizing" the outgoing edges. Note the 7130e6b6b59SJacob Faibussowitsch sync suffix does NOT refer to the host, i.e. this routine does NOT call 7140e6b6b59SJacob Faibussowitsch `PetscDeviceSynchronize()`. 715030f984aSJacob Faibussowitsch 7160e6b6b59SJacob Faibussowitsch If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC`. `dctx` waits for all sub contexts but 7170e6b6b59SJacob Faibussowitsch the sub contexts do not wait for one another or `dctx` afterwards. 718030f984aSJacob Faibussowitsch 719030f984aSJacob Faibussowitsch DAG representations: 720811af0c4SBarry Smith If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_DESTROY` 721030f984aSJacob Faibussowitsch .vb 722030f984aSJacob Faibussowitsch time -> 723030f984aSJacob Faibussowitsch 7240e6b6b59SJacob Faibussowitsch -> dctx ---------/- |= CALL =| - dctx -> 725030f984aSJacob Faibussowitsch -> dsub[0] -----/ 726030f984aSJacob Faibussowitsch -> ... -------/ 727030f984aSJacob Faibussowitsch -> dsub[n-1] -/ 728030f984aSJacob Faibussowitsch .ve 729811af0c4SBarry Smith If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_SYNC` 730030f984aSJacob Faibussowitsch .vb 731030f984aSJacob Faibussowitsch time -> 732030f984aSJacob Faibussowitsch 7330e6b6b59SJacob Faibussowitsch -> dctx ---------/- |= CALL =| -\----> dctx ------> 734030f984aSJacob Faibussowitsch -> dsub[0] -----/ \---> dsub[0] ---> 735030f984aSJacob Faibussowitsch -> ... -------/ \--> ... -------> 736030f984aSJacob Faibussowitsch -> dsub[n-1] -/ \-> dsub[n-1] -> 737030f984aSJacob Faibussowitsch .ve 7380e6b6b59SJacob Faibussowitsch If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC` 7390e6b6b59SJacob Faibussowitsch .vb 7400e6b6b59SJacob Faibussowitsch time -> 741030f984aSJacob Faibussowitsch 7420e6b6b59SJacob Faibussowitsch -> dctx ----------/- |= CALL =| - dctx -> 7430e6b6b59SJacob Faibussowitsch -> dsub[0] ------/-----------------------> 7440e6b6b59SJacob Faibussowitsch -> ... --------/------------------------> 7450e6b6b59SJacob Faibussowitsch -> dsub[n-1] --/-------------------------> 7460e6b6b59SJacob Faibussowitsch .ve 747030f984aSJacob Faibussowitsch 7480e6b6b59SJacob Faibussowitsch .N ASYNC_API 7490e6b6b59SJacob Faibussowitsch 7500e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextFork()`, `PetscDeviceContextForkWithStreamType()`, 7510e6b6b59SJacob Faibussowitsch `PetscDeviceContextSynchronize()`, `PetscDeviceContextJoinMode` 752030f984aSJacob Faibussowitsch @*/ 753d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextJoin(PetscDeviceContext dctx, PetscInt n, PetscDeviceContextJoinMode joinMode, PetscDeviceContext **dsub) 754d71ae5a4SJacob Faibussowitsch { 7550e6b6b59SJacob Faibussowitsch // debugging only 7560e6b6b59SJacob Faibussowitsch std::string idList; 757030f984aSJacob Faibussowitsch 758030f984aSJacob Faibussowitsch PetscFunctionBegin; 7590e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx)); 760030f984aSJacob Faibussowitsch /* validity of dctx is checked in the wait-for loop */ 7614f572ea9SToby Isaac PetscAssertPointer(dsub, 4); 762bf025ffbSJacob Faibussowitsch PetscAssert(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of contexts merged %" PetscInt_FMT " < 0", n); 763030f984aSJacob Faibussowitsch /* reserve 4 chars per id, 2 for number and 2 for ', ' separator */ 7640e6b6b59SJacob Faibussowitsch if (PetscDefined(USE_DEBUG_AND_INFO)) PetscCallCXX(idList.reserve(4 * n)); 765030f984aSJacob Faibussowitsch /* first dctx waits on all the incoming edges */ 7666a4a1270SPierre Jolivet PetscCall(PetscLogEventBegin(DCONTEXT_Join, dctx, nullptr, nullptr, nullptr)); 767030f984aSJacob Faibussowitsch for (PetscInt i = 0; i < n; ++i) { 768030f984aSJacob Faibussowitsch PetscCheckCompatibleDeviceContexts(dctx, 1, (*dsub)[i], 4); 7699566063dSJacob Faibussowitsch PetscCall(PetscDeviceContextWaitForContext(dctx, (*dsub)[i])); 7700e6b6b59SJacob Faibussowitsch if (PetscDefined(USE_DEBUG_AND_INFO)) { 7710e6b6b59SJacob Faibussowitsch PetscCallCXX(idList += std::to_string(PetscObjectCast((*dsub)[i])->id)); 7720e6b6b59SJacob Faibussowitsch if (i + 1 < n) PetscCallCXX(idList += ", "); 7730e6b6b59SJacob Faibussowitsch } 774030f984aSJacob Faibussowitsch } 775030f984aSJacob Faibussowitsch 776030f984aSJacob Faibussowitsch /* now we handle the aftermath */ 777030f984aSJacob Faibussowitsch switch (joinMode) { 7789371c9d4SSatish Balay case PETSC_DEVICE_CONTEXT_JOIN_DESTROY: { 7790e6b6b59SJacob Faibussowitsch const auto children = dctx->childIDs; 7800e6b6b59SJacob Faibussowitsch const auto maxchild = dctx->maxNumChildren; 7810e6b6b59SJacob Faibussowitsch auto &nchild = dctx->numChildren; 782030f984aSJacob Faibussowitsch PetscInt j = 0; 783030f984aSJacob Faibussowitsch 7840e6b6b59SJacob Faibussowitsch PetscCheck(n <= nchild, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Trying to destroy %" PetscInt_FMT " children of a parent context that only has %" PetscInt_FMT " children, likely trying to restore to wrong parent", n, nchild); 785030f984aSJacob Faibussowitsch /* update child count while it's still fresh in memory */ 7860e6b6b59SJacob Faibussowitsch nchild -= n; 7870e6b6b59SJacob Faibussowitsch for (PetscInt i = 0; i < maxchild; ++i) { 7880e6b6b59SJacob Faibussowitsch if (children[i] && (children[i] == PetscObjectCast((*dsub)[j])->id)) { 789030f984aSJacob Faibussowitsch /* child is one of ours, can destroy it */ 7909566063dSJacob Faibussowitsch PetscCall(PetscDeviceContextDestroy((*dsub) + j)); 791030f984aSJacob Faibussowitsch /* reset the child slot */ 7920e6b6b59SJacob Faibussowitsch children[i] = 0; 793030f984aSJacob Faibussowitsch if (++j == n) break; 794030f984aSJacob Faibussowitsch } 795030f984aSJacob Faibussowitsch } 7960e6b6b59SJacob Faibussowitsch /* gone through the loop but did not find every child */ 7970e6b6b59SJacob Faibussowitsch PetscCheck(j == n, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "%" PetscInt_FMT " 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); 7989566063dSJacob Faibussowitsch PetscCall(PetscFree(*dsub)); 7999371c9d4SSatish Balay } break; 800030f984aSJacob Faibussowitsch case PETSC_DEVICE_CONTEXT_JOIN_SYNC: 8019566063dSJacob Faibussowitsch for (PetscInt i = 0; i < n; ++i) PetscCall(PetscDeviceContextWaitForContext((*dsub)[i], dctx)); 802d71ae5a4SJacob Faibussowitsch case PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC: 803d71ae5a4SJacob Faibussowitsch break; 804d71ae5a4SJacob Faibussowitsch default: 805d71ae5a4SJacob Faibussowitsch SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown PetscDeviceContextJoinMode given"); 806030f984aSJacob Faibussowitsch } 8076a4a1270SPierre Jolivet PetscCall(PetscLogEventEnd(DCONTEXT_Join, dctx, nullptr, nullptr, nullptr)); 808030f984aSJacob Faibussowitsch 8090e6b6b59SJacob Faibussowitsch PetscCall(PetscDebugInfo(dctx, "Joined %" PetscInt_FMT " ctxs to ctx %" PetscInt64_FMT ", mode %s with IDs: %s\n", n, PetscObjectCast(dctx)->id, PetscDeviceContextJoinModes[joinMode], idList.c_str())); 8103ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 811030f984aSJacob Faibussowitsch } 812030f984aSJacob Faibussowitsch 81310450e9eSJacob Faibussowitsch // PetscClangLinter pragma disable: -fdoc-section-header-unknown 814030f984aSJacob Faibussowitsch /*@C 8150e6b6b59SJacob Faibussowitsch PetscDeviceContextSynchronize - Block the host until all work queued on a 8160e6b6b59SJacob Faibussowitsch `PetscDeviceContext` has finished 817030f984aSJacob Faibussowitsch 8180e6b6b59SJacob Faibussowitsch Not Collective 819030f984aSJacob Faibussowitsch 8202fe279fdSBarry Smith Input Parameter: 821811af0c4SBarry Smith . dctx - The `PetscDeviceContext` to synchronize 822030f984aSJacob Faibussowitsch 8232fe279fdSBarry Smith Level: beginner 8242fe279fdSBarry Smith 8250e6b6b59SJacob Faibussowitsch Notes: 8260e6b6b59SJacob Faibussowitsch The host will not return from this routine until `dctx` is idle. Any and all memory 8270e6b6b59SJacob Faibussowitsch operations queued on or otherwise associated with (either explicitly or implicitly via 8280e6b6b59SJacob Faibussowitsch dependencies) are guaranteed to have finished and be globally visible on return. 8290e6b6b59SJacob Faibussowitsch 8300e6b6b59SJacob Faibussowitsch In effect, this routine serves as memory and execution barrier. 8310e6b6b59SJacob Faibussowitsch 8320e6b6b59SJacob Faibussowitsch DAG representation: 8330e6b6b59SJacob Faibussowitsch .vb 8340e6b6b59SJacob Faibussowitsch time -> 8350e6b6b59SJacob Faibussowitsch 8360e6b6b59SJacob Faibussowitsch -> dctx - |= CALL =| - dctx -> 8370e6b6b59SJacob Faibussowitsch .ve 8380e6b6b59SJacob Faibussowitsch 839db781477SPatrick Sanan .seealso: `PetscDeviceContextFork()`, `PetscDeviceContextJoin()`, `PetscDeviceContextQueryIdle()` 840030f984aSJacob Faibussowitsch @*/ 841d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextSynchronize(PetscDeviceContext dctx) 842d71ae5a4SJacob Faibussowitsch { 843030f984aSJacob Faibussowitsch PetscFunctionBegin; 8440e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx)); 8456a4a1270SPierre Jolivet PetscCall(PetscLogEventBegin(DCONTEXT_Sync, dctx, nullptr, nullptr, nullptr)); 846030f984aSJacob Faibussowitsch /* if it isn't setup there is nothing to sync on */ 8470e6b6b59SJacob Faibussowitsch if (dctx->setup) { 8482f85e401SJacob Faibussowitsch PetscUseTypeMethod(dctx, synchronize); 8490e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextSyncClearMap_Internal(dctx)); 8500e6b6b59SJacob Faibussowitsch } 8516a4a1270SPierre Jolivet PetscCall(PetscLogEventEnd(DCONTEXT_Sync, dctx, nullptr, nullptr, nullptr)); 8523ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 853030f984aSJacob Faibussowitsch } 854030f984aSJacob Faibussowitsch 8550e6b6b59SJacob Faibussowitsch /* every device type has a vector of null PetscDeviceContexts -- one for each device */ 8560e6b6b59SJacob Faibussowitsch static auto nullContexts = std::array<std::vector<PetscDeviceContext>, PETSC_DEVICE_MAX>{}; 8570e6b6b59SJacob Faibussowitsch static auto nullContextsFinalizer = false; 858030f984aSJacob Faibussowitsch 859d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDeviceContextGetNullContextForDevice_Private(PetscBool user_set_device, PetscDevice device, PetscDeviceContext *dctx) 860d71ae5a4SJacob Faibussowitsch { 8610e6b6b59SJacob Faibussowitsch PetscInt devid; 8620e6b6b59SJacob Faibussowitsch PetscDeviceType dtype; 863a4af0ceeSJacob Faibussowitsch 864030f984aSJacob Faibussowitsch PetscFunctionBegin; 8650e6b6b59SJacob Faibussowitsch PetscValidDevice(device, 2); 8664f572ea9SToby Isaac PetscAssertPointer(dctx, 3); 8670e6b6b59SJacob Faibussowitsch if (PetscUnlikely(!nullContextsFinalizer)) { 8683048253cSJacob Faibussowitsch nullContextsFinalizer = true; 8693048253cSJacob Faibussowitsch PetscCall(PetscRegisterFinalize([] { 8700e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 8710e6b6b59SJacob Faibussowitsch for (auto &&dvec : nullContexts) { 8720e6b6b59SJacob Faibussowitsch for (auto &&dctx : dvec) PetscCall(PetscDeviceContextDestroy(&dctx)); 8730e6b6b59SJacob Faibussowitsch PetscCallCXX(dvec.clear()); 874030f984aSJacob Faibussowitsch } 8750e6b6b59SJacob Faibussowitsch nullContextsFinalizer = false; 8763ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 8773048253cSJacob Faibussowitsch })); 8780e6b6b59SJacob Faibussowitsch } 8790e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceGetDeviceId(device, &devid)); 8800e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceGetType(device, &dtype)); 8810e6b6b59SJacob Faibussowitsch { 8820e6b6b59SJacob Faibussowitsch auto &ctxlist = nullContexts[dtype]; 8830e6b6b59SJacob Faibussowitsch 8840e6b6b59SJacob Faibussowitsch PetscCheck(devid >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Device ID (%" PetscInt_FMT ") must be positive", devid); 8850e6b6b59SJacob Faibussowitsch // need to resize the container if not big enough because incrementing the iterator in 8860e6b6b59SJacob Faibussowitsch // std::next() (if we haven't initialized that ctx yet) may cause it to fall outside the 8870e6b6b59SJacob Faibussowitsch // current size of the container. 8880e6b6b59SJacob Faibussowitsch if (static_cast<std::size_t>(devid) >= ctxlist.size()) PetscCallCXX(ctxlist.resize(devid + 1)); 8890e6b6b59SJacob Faibussowitsch if (PetscUnlikely(!ctxlist[devid])) { 8900e6b6b59SJacob Faibussowitsch // we have not seen this device before 8910e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextCreate(dctx)); 892403f9ca4SJacob Faibussowitsch PetscCall(PetscInfo(*dctx, "Initializing null PetscDeviceContext (of type %s) for device %" PetscInt_FMT "\n", PetscDeviceTypes[dtype], devid)); 8930e6b6b59SJacob Faibussowitsch { 8940e6b6b59SJacob Faibussowitsch const auto pobj = PetscObjectCast(*dctx); 8950e6b6b59SJacob Faibussowitsch const auto name = "null context " + std::to_string(devid); 8960e6b6b59SJacob Faibussowitsch const auto prefix = "null_context_" + std::to_string(devid) + '_'; 8970e6b6b59SJacob Faibussowitsch 8980e6b6b59SJacob Faibussowitsch PetscCall(PetscObjectSetName(pobj, name.c_str())); 8990e6b6b59SJacob Faibussowitsch PetscCall(PetscObjectSetOptionsPrefix(pobj, prefix.c_str())); 9000e6b6b59SJacob Faibussowitsch } 9010e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextSetStreamType(*dctx, PETSC_STREAM_GLOBAL_BLOCKING)); 9020e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextSetDevice_Private(*dctx, device, user_set_device)); 9030e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextSetUp(*dctx)); 9040e6b6b59SJacob Faibussowitsch // would use ctxlist.cbegin() but GCC 4.8 can't handle const iterator insert! 9050e6b6b59SJacob Faibussowitsch PetscCallCXX(ctxlist.insert(std::next(ctxlist.begin(), devid), *dctx)); 9060e6b6b59SJacob Faibussowitsch } else *dctx = ctxlist[devid]; 9070e6b6b59SJacob Faibussowitsch } 9083ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 909030f984aSJacob Faibussowitsch } 910030f984aSJacob Faibussowitsch 9110e6b6b59SJacob Faibussowitsch /* 9120e6b6b59SJacob Faibussowitsch Gets the "NULL" context for the current PetscDeviceType and PetscDevice. NULL contexts are 9130e6b6b59SJacob Faibussowitsch guaranteed to always be globally blocking. 9140e6b6b59SJacob Faibussowitsch */ 915d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextGetNullContext_Internal(PetscDeviceContext *dctx) 916d71ae5a4SJacob Faibussowitsch { 9170e6b6b59SJacob Faibussowitsch PetscDeviceContext gctx; 9180e6b6b59SJacob Faibussowitsch PetscDevice gdev = nullptr; 919030f984aSJacob Faibussowitsch 920a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 9214f572ea9SToby Isaac PetscAssertPointer(dctx, 1); 9220e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetCurrentContext(&gctx)); 9230e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetDevice(gctx, &gdev)); 9240e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetNullContextForDevice_Private(gctx->usersetdevice, gdev, dctx)); 9253ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 926030f984aSJacob Faibussowitsch } 927030f984aSJacob Faibussowitsch 928030f984aSJacob Faibussowitsch /*@C 929811af0c4SBarry Smith PetscDeviceContextSetFromOptions - Configure a `PetscDeviceContext` from the options database 930030f984aSJacob Faibussowitsch 9310e6b6b59SJacob Faibussowitsch Collective on `comm` or `dctx` 932030f984aSJacob Faibussowitsch 933030f984aSJacob Faibussowitsch Input Parameters: 9340e6b6b59SJacob Faibussowitsch + comm - MPI communicator on which to query the options database (optional) 935811af0c4SBarry Smith - dctx - The `PetscDeviceContext` to configure 936030f984aSJacob Faibussowitsch 937030f984aSJacob Faibussowitsch Output Parameter: 938811af0c4SBarry Smith . dctx - The `PetscDeviceContext` 939030f984aSJacob Faibussowitsch 9403c7db156SBarry Smith Options Database Keys: 9410e6b6b59SJacob Faibussowitsch + -device_context_stream_type - type of stream to create inside the `PetscDeviceContext` - 9420e6b6b59SJacob Faibussowitsch `PetscDeviceContextSetStreamType()` 943811af0c4SBarry Smith - -device_context_device_type - the type of `PetscDevice` to attach by default - `PetscDeviceType` 944030f984aSJacob Faibussowitsch 9452fe279fdSBarry Smith Level: beginner 9462fe279fdSBarry Smith 9472fe279fdSBarry Smith Note: 9480e6b6b59SJacob Faibussowitsch The user may pass `MPI_COMM_NULL` for `comm` in which case the communicator of `dctx` is 9490e6b6b59SJacob Faibussowitsch used (which is always `PETSC_COMM_SELF`). 9500e6b6b59SJacob Faibussowitsch 9510e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextSetStreamType()`, `PetscDeviceContextSetDevice()`, 9520e6b6b59SJacob Faibussowitsch `PetscDeviceContextView()` 953030f984aSJacob Faibussowitsch @*/ 954d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetFromOptions(MPI_Comm comm, PetscDeviceContext dctx) 955d71ae5a4SJacob Faibussowitsch { 9560e6b6b59SJacob Faibussowitsch const auto pobj = PetscObjectCast(dctx); 9570e6b6b59SJacob Faibussowitsch auto dtype = std::make_pair(PETSC_DEVICE_DEFAULT(), PETSC_FALSE); 9580e6b6b59SJacob Faibussowitsch auto stype = std::make_pair(PETSC_DEVICE_CONTEXT_DEFAULT_STREAM_TYPE, PETSC_FALSE); 959e6b8bd2aSJacob Faibussowitsch MPI_Comm old_comm = PETSC_COMM_SELF; 960030f984aSJacob Faibussowitsch 961030f984aSJacob Faibussowitsch PetscFunctionBegin; 9620e6b6b59SJacob Faibussowitsch // do not user getoptionalnullcontext here, the user is not allowed to set it from options! 9630e6b6b59SJacob Faibussowitsch PetscValidDeviceContext(dctx, 2); 9640e6b6b59SJacob Faibussowitsch /* set the device type first */ 9650e6b6b59SJacob Faibussowitsch if (const auto device = dctx->device) PetscCall(PetscDeviceGetType(device, &dtype.first)); 9660e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetStreamType(dctx, &stype.first)); 9670e6b6b59SJacob Faibussowitsch 9680e6b6b59SJacob Faibussowitsch if (comm == MPI_COMM_NULL) { 9690e6b6b59SJacob Faibussowitsch PetscCall(PetscObjectGetComm(pobj, &comm)); 9700e6b6b59SJacob Faibussowitsch } else { 9710e6b6b59SJacob Faibussowitsch // briefly set the communicator for dctx (it is always PETSC_COMM_SELF) so 9720e6b6b59SJacob Faibussowitsch // PetscObjectOptionsBegin() behaves as if dctx had comm 9730e6b6b59SJacob Faibussowitsch old_comm = Petsc::util::exchange(pobj->comm, comm); 9740e6b6b59SJacob Faibussowitsch } 9750e6b6b59SJacob Faibussowitsch 9760e6b6b59SJacob Faibussowitsch PetscObjectOptionsBegin(pobj); 9770e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextQueryOptions_Internal(PetscOptionsObject, dtype, stype)); 978d0609cedSBarry Smith PetscOptionsEnd(); 9790e6b6b59SJacob Faibussowitsch // reset the comm (should be PETSC_COMM_SELF) 9800e6b6b59SJacob Faibussowitsch if (comm != MPI_COMM_NULL) pobj->comm = old_comm; 9810e6b6b59SJacob Faibussowitsch if (dtype.second) PetscCall(PetscDeviceContextSetDefaultDeviceForType_Internal(dctx, dtype.first)); 9820e6b6b59SJacob Faibussowitsch if (stype.second) PetscCall(PetscDeviceContextSetStreamType(dctx, stype.first)); 9830e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextSetUp(dctx)); 9843ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 9850e6b6b59SJacob Faibussowitsch } 9860e6b6b59SJacob Faibussowitsch 9870e6b6b59SJacob Faibussowitsch /*@C 9880e6b6b59SJacob Faibussowitsch PetscDeviceContextView - View a `PetscDeviceContext` 9890e6b6b59SJacob Faibussowitsch 9900e6b6b59SJacob Faibussowitsch Collective on `viewer` 9910e6b6b59SJacob Faibussowitsch 9920e6b6b59SJacob Faibussowitsch Input Parameters: 9930e6b6b59SJacob Faibussowitsch + dctx - The `PetscDeviceContext` 9940e6b6b59SJacob Faibussowitsch - viewer - The `PetscViewer` to view `dctx` with (may be `NULL`) 9950e6b6b59SJacob Faibussowitsch 9962fe279fdSBarry Smith Level: beginner 9972fe279fdSBarry Smith 9982fe279fdSBarry Smith Note: 9990e6b6b59SJacob Faibussowitsch If `viewer` is `NULL`, `PETSC_VIEWER_STDOUT_WORLD` is used instead, in which case this 10000e6b6b59SJacob Faibussowitsch routine is collective on `PETSC_COMM_WORLD`. 10010e6b6b59SJacob Faibussowitsch 10020e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextViewFromOptions()`, `PetscDeviceView()`, `PETSC_VIEWER_STDOUT_WORLD`, `PetscDeviceContextCreate()` 10030e6b6b59SJacob Faibussowitsch @*/ 1004d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextView(PetscDeviceContext dctx, PetscViewer viewer) 1005d71ae5a4SJacob Faibussowitsch { 10060e6b6b59SJacob Faibussowitsch PetscBool iascii; 10070e6b6b59SJacob Faibussowitsch 10080e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 10090e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx)); 10100e6b6b59SJacob Faibussowitsch if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PETSC_COMM_WORLD, &viewer)); 10110e6b6b59SJacob Faibussowitsch PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 10120e6b6b59SJacob Faibussowitsch PetscCall(PetscObjectTypeCompare(PetscObjectCast(viewer), PETSCVIEWERASCII, &iascii)); 10130e6b6b59SJacob Faibussowitsch if (iascii) { 10140e6b6b59SJacob Faibussowitsch auto stype = PETSC_STREAM_DEFAULT_BLOCKING; 10150e6b6b59SJacob Faibussowitsch PetscViewer sub; 10160e6b6b59SJacob Faibussowitsch 10170e6b6b59SJacob Faibussowitsch PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sub)); 10180e6b6b59SJacob Faibussowitsch PetscCall(PetscObjectPrintClassNamePrefixType(PetscObjectCast(dctx), sub)); 10190e6b6b59SJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(sub)); 10200e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetStreamType(dctx, &stype)); 10210e6b6b59SJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(sub, "stream type: %s\n", PetscStreamTypes[stype])); 10220e6b6b59SJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(sub, "children: %" PetscInt_FMT "\n", dctx->numChildren)); 10230e6b6b59SJacob Faibussowitsch if (const auto nchild = dctx->numChildren) { 10240e6b6b59SJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(sub)); 10250e6b6b59SJacob Faibussowitsch for (PetscInt i = 0; i < nchild; ++i) { 10260e6b6b59SJacob Faibussowitsch if (i == nchild - 1) { 10270e6b6b59SJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(sub, "%" PetscInt64_FMT, dctx->childIDs[i])); 10280e6b6b59SJacob Faibussowitsch } else { 10290e6b6b59SJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(sub, "%" PetscInt64_FMT ", ", dctx->childIDs[i])); 10300e6b6b59SJacob Faibussowitsch } 10310e6b6b59SJacob Faibussowitsch } 10320e6b6b59SJacob Faibussowitsch } 10330e6b6b59SJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(sub)); 10340e6b6b59SJacob Faibussowitsch PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sub)); 10350e6b6b59SJacob Faibussowitsch PetscCall(PetscViewerFlush(viewer)); 10360e6b6b59SJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer)); 10370e6b6b59SJacob Faibussowitsch } 10380e6b6b59SJacob Faibussowitsch if (const auto device = dctx->device) PetscCall(PetscDeviceView(device, viewer)); 10390e6b6b59SJacob Faibussowitsch if (iascii) PetscCall(PetscViewerASCIIPopTab(viewer)); 10403ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 10410e6b6b59SJacob Faibussowitsch } 10420e6b6b59SJacob Faibussowitsch 10430e6b6b59SJacob Faibussowitsch /*@C 10440e6b6b59SJacob Faibussowitsch PetscDeviceContextViewFromOptions - View a `PetscDeviceContext` from options 10450e6b6b59SJacob Faibussowitsch 10460e6b6b59SJacob Faibussowitsch Input Parameters: 10470e6b6b59SJacob Faibussowitsch + dctx - The `PetscDeviceContext` to view 10480e6b6b59SJacob Faibussowitsch . obj - Optional `PetscObject` to associate (may be `NULL`) 10490e6b6b59SJacob Faibussowitsch - name - The command line option 10500e6b6b59SJacob Faibussowitsch 10510e6b6b59SJacob Faibussowitsch Level: beginner 10520e6b6b59SJacob Faibussowitsch 10530e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextView()`, `PetscObjectViewFromOptions()`, `PetscDeviceContextCreate()` 10540e6b6b59SJacob Faibussowitsch @*/ 1055d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextViewFromOptions(PetscDeviceContext dctx, PetscObject obj, const char name[]) 1056d71ae5a4SJacob Faibussowitsch { 10570e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 10580e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx)); 10590e6b6b59SJacob Faibussowitsch if (obj) PetscValidHeader(obj, 2); 10604f572ea9SToby Isaac PetscAssertPointer(name, 3); 10610e6b6b59SJacob Faibussowitsch PetscCall(PetscObjectViewFromOptions(PetscObjectCast(dctx), obj, name)); 10623ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1063030f984aSJacob Faibussowitsch } 106431d47070SJunchao Zhang 106531d47070SJunchao Zhang /*@C 106631d47070SJunchao Zhang PetscDeviceContextGetStreamHandle - Return a handle to the underlying stream of the current device context 106731d47070SJunchao Zhang 106831d47070SJunchao Zhang Input Parameters: 106931d47070SJunchao Zhang + dctx - The `PetscDeviceContext` to get the stream from 107031d47070SJunchao Zhang - handle - A handle to the stream 107131d47070SJunchao Zhang 107231d47070SJunchao Zhang Level: developer 107331d47070SJunchao Zhang 107431d47070SJunchao Zhang Note: 107531d47070SJunchao Zhang This routine is dangerous. It exists only for the most experienced users and 107631d47070SJunchao Zhang internal PETSc developement. 107731d47070SJunchao Zhang 107831d47070SJunchao Zhang There is no way for PETSc's auto-dependency system to track what the caller does with the 107931d47070SJunchao Zhang stream. 108031d47070SJunchao Zhang 108131d47070SJunchao Zhang If the user uses the stream to copy memory that was previously modified by PETSc, or launches 108231d47070SJunchao Zhang kernels that modify memory with the stream, it is the users responsibility to inform PETSc of 108331d47070SJunchao Zhang their actions via `PetscDeviceContextMarkIntentFromID()`. Failure to do so may introduce a 108431d47070SJunchao Zhang race condition. This race condition may manifest in nondeterministic ways. 108531d47070SJunchao Zhang 108631d47070SJunchao Zhang Alternatively, the user may synchronize the stream immediately before and after use. This is 108731d47070SJunchao Zhang the safest option. 108831d47070SJunchao Zhang 108931d47070SJunchao Zhang Example Usage: 109031d47070SJunchao Zhang .vb 109131d47070SJunchao Zhang PetscDeviceContext dctx; 109231d47070SJunchao Zhang PetscDeviceType type; 109331d47070SJunchao Zhang void *handle; 109431d47070SJunchao Zhang 109531d47070SJunchao Zhang PetscDeviceContextGetCurrentContext(&dctx); 109631d47070SJunchao Zhang PetscDeviceContextGetStreamHandle(dctx, &handle); 109731d47070SJunchao Zhang PetscDeviceContextGetDeviceType(dctx, &type); 109831d47070SJunchao Zhang 109931d47070SJunchao Zhang if (type == PETSC_DEVICE_CUDA) { 110031d47070SJunchao Zhang cudsStream_t stream = *(cudaStream_t*)handle; 110131d47070SJunchao Zhang 110231d47070SJunchao Zhang my_cuda_kernel<<<1, 2, 3, stream>>>(); 110331d47070SJunchao Zhang } 110431d47070SJunchao Zhang .ve 110531d47070SJunchao Zhang 110631d47070SJunchao Zhang .N ASYNC_API 110731d47070SJunchao Zhang 110831d47070SJunchao Zhang .seealso: `PetscDeviceContext` 110931d47070SJunchao Zhang @*/ 111031d47070SJunchao Zhang PetscErrorCode PetscDeviceContextGetStreamHandle(PetscDeviceContext dctx, void *handle) 111131d47070SJunchao Zhang { 111231d47070SJunchao Zhang PetscFunctionBegin; 111331d47070SJunchao Zhang PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx)); 11144f572ea9SToby Isaac PetscAssertPointer(handle, 2); 111597cd0981SJacob Faibussowitsch PetscCall(PetscDeviceContextGetStreamHandle_Internal(dctx, (void **)handle)); 111631d47070SJunchao Zhang PetscFunctionReturn(PETSC_SUCCESS); 111731d47070SJunchao Zhang } 1118