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)); 19146a86ebSJacob Faibussowitsch PetscCallCXX(PetscObjectCast(dctx)->cpp = new CxxData()); 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()); 530e6b6b59SJacob Faibussowitsch } 54030f984aSJacob Faibussowitsch dctx->streamType = PETSC_STREAM_DEFAULT_BLOCKING; 553ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 56030f984aSJacob Faibussowitsch } 57146a86ebSJacob Faibussowitsch 58089fb57cSJacob Faibussowitsch static PetscErrorCode invalidate_(PetscDeviceContext) noexcept { return PETSC_SUCCESS; } 59030f984aSJacob Faibussowitsch }; 60030f984aSJacob Faibussowitsch 61146a86ebSJacob Faibussowitsch static Petsc::ObjectPool<_p_PetscDeviceContext, PetscDeviceContextConstructor> contextPool; 62030f984aSJacob Faibussowitsch 63*10450e9eSJacob Faibussowitsch // PetscClangLinter pragma disable: -fdoc-section-header-unknown 64030f984aSJacob Faibussowitsch /*@C 65811af0c4SBarry Smith PetscDeviceContextCreate - Creates a `PetscDeviceContext` 66030f984aSJacob Faibussowitsch 670e6b6b59SJacob Faibussowitsch Not Collective 68030f984aSJacob Faibussowitsch 69d5b43468SJose E. Roman Output Parameter: 70811af0c4SBarry Smith . dctx - The `PetscDeviceContext` 71030f984aSJacob Faibussowitsch 722fe279fdSBarry Smith Level: beginner 732fe279fdSBarry Smith 74811af0c4SBarry Smith Note: 75030f984aSJacob Faibussowitsch Unlike almost every other PETSc class it is advised that most users use 760e6b6b59SJacob Faibussowitsch `PetscDeviceContextDuplicate()` rather than this routine to create new contexts. Contexts of 770e6b6b59SJacob Faibussowitsch different types are incompatible with one another; using `PetscDeviceContextDuplicate()` 780e6b6b59SJacob Faibussowitsch ensures compatible types. 790e6b6b59SJacob Faibussowitsch 800e6b6b59SJacob Faibussowitsch DAG representation: 810e6b6b59SJacob Faibussowitsch .vb 820e6b6b59SJacob Faibussowitsch time -> 830e6b6b59SJacob Faibussowitsch 840e6b6b59SJacob Faibussowitsch |= CALL =| - dctx -> 850e6b6b59SJacob Faibussowitsch .ve 86030f984aSJacob Faibussowitsch 870e6b6b59SJacob Faibussowitsch .N ASYNC_API 880e6b6b59SJacob Faibussowitsch 89db781477SPatrick Sanan .seealso: `PetscDeviceContextDuplicate()`, `PetscDeviceContextSetDevice()`, 90db781477SPatrick Sanan `PetscDeviceContextSetStreamType()`, `PetscDeviceContextSetUp()`, 910e6b6b59SJacob Faibussowitsch `PetscDeviceContextSetFromOptions()`, `PetscDeviceContextView()`, `PetscDeviceContextDestroy()` 92030f984aSJacob Faibussowitsch @*/ 93d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextCreate(PetscDeviceContext *dctx) 94d71ae5a4SJacob Faibussowitsch { 95030f984aSJacob Faibussowitsch PetscFunctionBegin; 96030f984aSJacob Faibussowitsch PetscValidPointer(dctx, 1); 979566063dSJacob Faibussowitsch PetscCall(PetscDeviceInitializePackage()); 986a4a1270SPierre Jolivet PetscCall(PetscLogEventBegin(DCONTEXT_Create, nullptr, nullptr, nullptr, nullptr)); 990e6b6b59SJacob Faibussowitsch PetscCall(contextPool.allocate(dctx)); 1006a4a1270SPierre Jolivet PetscCall(PetscLogEventEnd(DCONTEXT_Create, nullptr, nullptr, nullptr, nullptr)); 1013ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 102030f984aSJacob Faibussowitsch } 103030f984aSJacob Faibussowitsch 104*10450e9eSJacob Faibussowitsch // PetscClangLinter pragma disable: -fdoc-section-header-unknown 105030f984aSJacob Faibussowitsch /*@C 106811af0c4SBarry Smith PetscDeviceContextDestroy - Frees a `PetscDeviceContext` 107030f984aSJacob Faibussowitsch 1080e6b6b59SJacob Faibussowitsch Not Collective 109030f984aSJacob Faibussowitsch 1102fe279fdSBarry Smith Input Parameter: 111811af0c4SBarry Smith . dctx - The `PetscDeviceContext` 112030f984aSJacob Faibussowitsch 1132fe279fdSBarry Smith Level: beginner 1142fe279fdSBarry Smith 1150e6b6b59SJacob Faibussowitsch Notes: 1160e6b6b59SJacob Faibussowitsch No implicit synchronization occurs due to this routine, all resources are released completely 1170e6b6b59SJacob Faibussowitsch asynchronously w.r.t. the host. If one needs to guarantee access to the data produced on 1180e6b6b59SJacob Faibussowitsch `dctx`'s stream the user is responsible for calling `PetscDeviceContextSynchronize()` before 1190e6b6b59SJacob Faibussowitsch calling this routine. 120030f984aSJacob Faibussowitsch 121da81f932SPierre Jolivet DAG representation: 1220e6b6b59SJacob Faibussowitsch .vb 1230e6b6b59SJacob Faibussowitsch time -> 1240e6b6b59SJacob Faibussowitsch 1250e6b6b59SJacob Faibussowitsch -> dctx - |= CALL =| 1260e6b6b59SJacob Faibussowitsch .ve 1270e6b6b59SJacob Faibussowitsch 1280e6b6b59SJacob Faibussowitsch Developer Notes: 1290e6b6b59SJacob Faibussowitsch `dctx` is never actually "destroyed" in the classical sense. It is returned to an ever 1300e6b6b59SJacob Faibussowitsch growing pool of `PetscDeviceContext`s. There are currently no limits on the size of the pool, 1310e6b6b59SJacob Faibussowitsch this should perhaps be implemented. 132030f984aSJacob Faibussowitsch 1330e6b6b59SJacob Faibussowitsch .N ASYNC_API 1340e6b6b59SJacob Faibussowitsch 1350e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextSetDevice()`, 1360e6b6b59SJacob Faibussowitsch `PetscDeviceContextSetUp()`, `PetscDeviceContextSynchronize()` 137030f984aSJacob Faibussowitsch @*/ 138d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextDestroy(PetscDeviceContext *dctx) 139d71ae5a4SJacob Faibussowitsch { 140030f984aSJacob Faibussowitsch PetscFunctionBegin; 1410e6b6b59SJacob Faibussowitsch PetscValidPointer(dctx, 1); 1423ba16761SJacob Faibussowitsch if (!*dctx) PetscFunctionReturn(PETSC_SUCCESS); 1436a4a1270SPierre Jolivet PetscCall(PetscLogEventBegin(DCONTEXT_Destroy, nullptr, nullptr, nullptr, nullptr)); 1440e6b6b59SJacob Faibussowitsch if (--(PetscObjectCast(*dctx)->refct) <= 0) { 1450e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextCheckNotOrphaned_Internal(*dctx)); 146146a86ebSJacob Faibussowitsch PetscCall(contextPool.deallocate(dctx)); 1470e6b6b59SJacob Faibussowitsch } 1486a4a1270SPierre Jolivet PetscCall(PetscLogEventEnd(DCONTEXT_Destroy, nullptr, nullptr, nullptr, nullptr)); 149bf025ffbSJacob Faibussowitsch *dctx = nullptr; 1503ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 151030f984aSJacob Faibussowitsch } 152030f984aSJacob Faibussowitsch 153030f984aSJacob Faibussowitsch /*@C 1540e6b6b59SJacob Faibussowitsch PetscDeviceContextSetStreamType - Set the implementation type of the underlying stream for a 1550e6b6b59SJacob Faibussowitsch `PetscDeviceContext` 156030f984aSJacob Faibussowitsch 1570e6b6b59SJacob Faibussowitsch Not Collective 158030f984aSJacob Faibussowitsch 15901d2d390SJose E. Roman Input Parameters: 160811af0c4SBarry Smith + dctx - The `PetscDeviceContext` 161811af0c4SBarry Smith - type - The `PetscStreamType` 162030f984aSJacob Faibussowitsch 1632fe279fdSBarry Smith Level: beginner 1642fe279fdSBarry Smith 1652fe279fdSBarry Smith Note: 166811af0c4SBarry Smith See `PetscStreamType` in `include/petscdevicetypes.h` for more information on the available 1670e6b6b59SJacob Faibussowitsch types and their interactions. If the `PetscDeviceContext` was previously set up and stream 168811af0c4SBarry Smith type was changed, you must call `PetscDeviceContextSetUp()` again after this routine. 169030f984aSJacob Faibussowitsch 1700e6b6b59SJacob Faibussowitsch .seealso: `PetscStreamType`, `PetscDeviceContextGetStreamType()`, `PetscDeviceContextCreate()`, 1710e6b6b59SJacob Faibussowitsch `PetscDeviceContextSetUp()`, `PetscDeviceContextSetFromOptions()` 172030f984aSJacob Faibussowitsch @*/ 173d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetStreamType(PetscDeviceContext dctx, PetscStreamType type) 174d71ae5a4SJacob Faibussowitsch { 175030f984aSJacob Faibussowitsch PetscFunctionBegin; 1760e6b6b59SJacob Faibussowitsch // do not use getoptionalnullcontext here since we do not want the user to change the stream 1770e6b6b59SJacob Faibussowitsch // type 178030f984aSJacob Faibussowitsch PetscValidDeviceContext(dctx, 1); 179030f984aSJacob Faibussowitsch PetscValidStreamType(type, 2); 1800e6b6b59SJacob Faibussowitsch // only need to do complex swapping if the object has already been setup 181030f984aSJacob Faibussowitsch if (dctx->setup && (dctx->streamType != type)) { 182030f984aSJacob Faibussowitsch dctx->setup = PETSC_FALSE; 1836a4a1270SPierre Jolivet PetscCall(PetscLogEventBegin(DCONTEXT_ChangeStream, dctx, nullptr, nullptr, nullptr)); 1840e6b6b59SJacob Faibussowitsch PetscUseTypeMethod(dctx, changestreamtype, type); 1856a4a1270SPierre Jolivet PetscCall(PetscLogEventEnd(DCONTEXT_ChangeStream, dctx, nullptr, nullptr, nullptr)); 186030f984aSJacob Faibussowitsch } 187030f984aSJacob Faibussowitsch dctx->streamType = type; 1883ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 189030f984aSJacob Faibussowitsch } 190030f984aSJacob Faibussowitsch 191030f984aSJacob Faibussowitsch /*@C 1920e6b6b59SJacob Faibussowitsch PetscDeviceContextGetStreamType - Get the implementation type of the underlying stream for a 1930e6b6b59SJacob Faibussowitsch `PetscDeviceContext` 194030f984aSJacob Faibussowitsch 1950e6b6b59SJacob Faibussowitsch Not Collective 196030f984aSJacob Faibussowitsch 19701d2d390SJose E. Roman Input Parameter: 198811af0c4SBarry Smith . dctx - The `PetscDeviceContext` 199030f984aSJacob Faibussowitsch 200030f984aSJacob Faibussowitsch Output Parameter: 201811af0c4SBarry Smith . type - The `PetscStreamType` 202030f984aSJacob Faibussowitsch 2032fe279fdSBarry Smith Level: beginner 2042fe279fdSBarry Smith 2052fe279fdSBarry Smith Note: 2060e6b6b59SJacob Faibussowitsch See `PetscStreamType` in `include/petscdevicetypes.h` for more information on the available 2070e6b6b59SJacob Faibussowitsch types and their interactions 208030f984aSJacob Faibussowitsch 2090e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextSetStreamType()`, `PetscDeviceContextCreate()`, 2100e6b6b59SJacob Faibussowitsch `PetscDeviceContextSetFromOptions()` 211030f984aSJacob Faibussowitsch @*/ 212d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextGetStreamType(PetscDeviceContext dctx, PetscStreamType *type) 213d71ae5a4SJacob Faibussowitsch { 214030f984aSJacob Faibussowitsch PetscFunctionBegin; 2150e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx)); 216030f984aSJacob Faibussowitsch PetscValidIntPointer(type, 2); 217030f984aSJacob Faibussowitsch *type = dctx->streamType; 2183ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 219030f984aSJacob Faibussowitsch } 220030f984aSJacob Faibussowitsch 2210e6b6b59SJacob Faibussowitsch /* 2220e6b6b59SJacob Faibussowitsch Actual function to set the device. 223030f984aSJacob Faibussowitsch 2240e6b6b59SJacob Faibussowitsch 1. Repeatedly destroying and recreating internal data structures (like streams and events) 2250e6b6b59SJacob Faibussowitsch for recycled PetscDeviceContexts is not free. If done often, it does add up. 2260e6b6b59SJacob Faibussowitsch 2. The vast majority of PetscDeviceContexts are created by PETSc either as children or 22735cb6cd3SPierre Jolivet default contexts. The default contexts *never* change type, and the children are extremely 2280e6b6b59SJacob Faibussowitsch unlikely to (chances are if you fork once, you will fork again very soon). 2290e6b6b59SJacob Faibussowitsch 3. The only time this calculus changes is if the user themselves sets the device type. In 2300e6b6b59SJacob Faibussowitsch this case we do not know what the user has changed, so must always wipe the slate clean. 2310e6b6b59SJacob Faibussowitsch 2320e6b6b59SJacob Faibussowitsch Thus we need to keep track whether the user explicitly sets the device contexts device. 2330e6b6b59SJacob Faibussowitsch */ 234d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDeviceContextSetDevice_Private(PetscDeviceContext dctx, PetscDevice device, PetscBool user_set) 235d71ae5a4SJacob Faibussowitsch { 2360e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 2370e6b6b59SJacob Faibussowitsch // do not use getoptionalnullcontext here since we do not want the user to change its device 2380e6b6b59SJacob Faibussowitsch PetscValidDeviceContext(dctx, 1); 2390e6b6b59SJacob Faibussowitsch PetscValidDevice(device, 2); 2403ba16761SJacob Faibussowitsch if (dctx->device && (dctx->device->id == device->id)) PetscFunctionReturn(PETSC_SUCCESS); 2416a4a1270SPierre Jolivet PetscCall(PetscLogEventBegin(DCONTEXT_SetDevice, dctx, nullptr, nullptr, nullptr)); 2422126a61dSJacob Faibussowitsch PetscTryTypeMethod(dctx, destroy); 2430e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceDestroy(&dctx->device)); 2440e6b6b59SJacob Faibussowitsch PetscCall(PetscMemzero(dctx->ops, sizeof(*dctx->ops))); 2452126a61dSJacob Faibussowitsch PetscCall(PetscDeviceReference_Internal(device)); 2462126a61dSJacob Faibussowitsch // set it before calling the method 2472126a61dSJacob Faibussowitsch dctx->device = device; 2480e6b6b59SJacob Faibussowitsch PetscCall((*device->ops->createcontext)(dctx)); 2496a4a1270SPierre Jolivet PetscCall(PetscLogEventEnd(DCONTEXT_SetDevice, dctx, nullptr, nullptr, nullptr)); 2500e6b6b59SJacob Faibussowitsch dctx->setup = PETSC_FALSE; 2510e6b6b59SJacob Faibussowitsch dctx->usersetdevice = user_set; 2523ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2530e6b6b59SJacob Faibussowitsch } 2540e6b6b59SJacob Faibussowitsch 255d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetDefaultDeviceForType_Internal(PetscDeviceContext dctx, PetscDeviceType type) 256d71ae5a4SJacob Faibussowitsch { 2570e6b6b59SJacob Faibussowitsch PetscDevice device; 2580e6b6b59SJacob Faibussowitsch 2590e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 2600e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceGetDefaultForType_Internal(type, &device)); 2610e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextSetDevice_Private(dctx, device, PETSC_FALSE)); 2623ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2630e6b6b59SJacob Faibussowitsch } 2640e6b6b59SJacob Faibussowitsch 2650e6b6b59SJacob Faibussowitsch /*@C 2660e6b6b59SJacob Faibussowitsch PetscDeviceContextSetDevice - Set the underlying `PetscDevice` for a `PetscDeviceContext` 2670e6b6b59SJacob Faibussowitsch 2680e6b6b59SJacob Faibussowitsch Not Collective 269030f984aSJacob Faibussowitsch 27001d2d390SJose E. Roman Input Parameters: 271811af0c4SBarry Smith + dctx - The `PetscDeviceContext` 272811af0c4SBarry Smith - device - The `PetscDevice` 273030f984aSJacob Faibussowitsch 2742fe279fdSBarry Smith Level: intermediate 2752fe279fdSBarry Smith 276030f984aSJacob Faibussowitsch Notes: 2770e6b6b59SJacob Faibussowitsch This routine is effectively `PetscDeviceContext`'s "set-type" (so every `PetscDeviceContext` must 278da81f932SPierre Jolivet also have an attached `PetscDevice`). Unlike the usual set-type semantics, it is not strictly 2790e6b6b59SJacob Faibussowitsch necessary to set a contexts device to enable usage, any created `PetscDeviceContext`s will 2800e6b6b59SJacob Faibussowitsch always come equipped with the "default" device. 281030f984aSJacob Faibussowitsch 2820e6b6b59SJacob Faibussowitsch This routine is a no-op if `device` is already attached to `dctx`. 283a4af0ceeSJacob Faibussowitsch 2840e6b6b59SJacob Faibussowitsch This routine may (but is very unlikely to) initialize the backend device and may incur 2850e6b6b59SJacob Faibussowitsch synchronization. 2865181c4f9SJacob Faibussowitsch 2870e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceCreate()`, `PetscDeviceConfigure()`, `PetscDeviceContextGetDevice()`, 2880e6b6b59SJacob Faibussowitsch `PetscDeviceContextGetDeviceType()` 289030f984aSJacob Faibussowitsch @*/ 290d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetDevice(PetscDeviceContext dctx, PetscDevice device) 291d71ae5a4SJacob Faibussowitsch { 292030f984aSJacob Faibussowitsch PetscFunctionBegin; 2930e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextSetDevice_Private(dctx, device, PETSC_TRUE)); 2943ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 295030f984aSJacob Faibussowitsch } 296030f984aSJacob Faibussowitsch 297030f984aSJacob Faibussowitsch /*@C 298811af0c4SBarry Smith PetscDeviceContextGetDevice - Get the underlying `PetscDevice` for a `PetscDeviceContext` 299030f984aSJacob Faibussowitsch 3000e6b6b59SJacob Faibussowitsch Not Collective 301030f984aSJacob Faibussowitsch 302030f984aSJacob Faibussowitsch Input Parameter: 303811af0c4SBarry Smith . dctx - the `PetscDeviceContext` 304030f984aSJacob Faibussowitsch 305030f984aSJacob Faibussowitsch Output Parameter: 306811af0c4SBarry Smith . device - The `PetscDevice` 307030f984aSJacob Faibussowitsch 308a375dbeeSPatrick Sanan Level: intermediate 309a375dbeeSPatrick Sanan 3102fe279fdSBarry Smith Note: 3112fe279fdSBarry Smith This is a borrowed reference, the user should not destroy `device`. 3122fe279fdSBarry Smith 3130e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextSetDevice()`, `PetscDevice`, `PetscDeviceContextGetDeviceType()` 314030f984aSJacob Faibussowitsch @*/ 315d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextGetDevice(PetscDeviceContext dctx, PetscDevice *device) 316d71ae5a4SJacob Faibussowitsch { 317030f984aSJacob Faibussowitsch PetscFunctionBegin; 3180e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx)); 319030f984aSJacob Faibussowitsch PetscValidPointer(device, 2); 3200e6b6b59SJacob Faibussowitsch PetscAssert(dctx->device, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "PetscDeviceContext %" PetscInt64_FMT " has no attached PetscDevice to get", PetscObjectCast(dctx)->id); 321030f984aSJacob Faibussowitsch *device = dctx->device; 3223ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 323030f984aSJacob Faibussowitsch } 324030f984aSJacob Faibussowitsch 325030f984aSJacob Faibussowitsch /*@C 3260e6b6b59SJacob Faibussowitsch PetscDeviceContextGetDeviceType - Get the `PetscDeviceType` for a `PetscDeviceContext` 3270e6b6b59SJacob Faibussowitsch 3280e6b6b59SJacob Faibussowitsch Not Collective 3290e6b6b59SJacob Faibussowitsch 3300e6b6b59SJacob Faibussowitsch Input Parameter: 3310e6b6b59SJacob Faibussowitsch . dctx - The `PetscDeviceContext` 3320e6b6b59SJacob Faibussowitsch 3330e6b6b59SJacob Faibussowitsch Output Parameter: 3340e6b6b59SJacob Faibussowitsch . type - The `PetscDeviceType` 3350e6b6b59SJacob Faibussowitsch 3362fe279fdSBarry Smith Level: beginner 3372fe279fdSBarry Smith 3382fe279fdSBarry Smith Note: 3390e6b6b59SJacob Faibussowitsch This routine is a convenience shorthand for `PetscDeviceContextGetDevice()` -> 3400e6b6b59SJacob Faibussowitsch `PetscDeviceGetType()`. 3410e6b6b59SJacob Faibussowitsch 3420e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceType`, `PetscDeviceContextGetDevice()`, `PetscDeviceGetType()`, `PetscDevice` 3430e6b6b59SJacob Faibussowitsch @*/ 344d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextGetDeviceType(PetscDeviceContext dctx, PetscDeviceType *type) 345d71ae5a4SJacob Faibussowitsch { 3460e6b6b59SJacob Faibussowitsch PetscDevice device = nullptr; 3470e6b6b59SJacob Faibussowitsch 3480e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 3490e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx)); 3500e6b6b59SJacob Faibussowitsch PetscValidPointer(type, 2); 3510e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetDevice(dctx, &device)); 3520e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceGetType(device, type)); 3533ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3540e6b6b59SJacob Faibussowitsch } 3550e6b6b59SJacob Faibussowitsch 3560e6b6b59SJacob Faibussowitsch /*@C 357811af0c4SBarry Smith PetscDeviceContextSetUp - Prepares a `PetscDeviceContext` for use 358030f984aSJacob Faibussowitsch 3590e6b6b59SJacob Faibussowitsch Not Collective 360030f984aSJacob Faibussowitsch 36101d2d390SJose E. Roman Input Parameter: 362811af0c4SBarry Smith . dctx - The `PetscDeviceContext` 363030f984aSJacob Faibussowitsch 3642fe279fdSBarry Smith Level: beginner 3652fe279fdSBarry Smith 366aec76313SJacob Faibussowitsch Developer Notes: 3670e6b6b59SJacob Faibussowitsch This routine is usually the stage where a `PetscDeviceContext` acquires device-side data 3680e6b6b59SJacob Faibussowitsch structures such as streams, events, and (possibly) handles. 369030f984aSJacob Faibussowitsch 3700e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextSetDevice()`, 3710e6b6b59SJacob Faibussowitsch `PetscDeviceContextDestroy()`, `PetscDeviceContextSetFromOptions()` 372030f984aSJacob Faibussowitsch @*/ 373d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetUp(PetscDeviceContext dctx) 374d71ae5a4SJacob Faibussowitsch { 375030f984aSJacob Faibussowitsch PetscFunctionBegin; 3760e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx)); 3773ba16761SJacob Faibussowitsch if (dctx->setup) PetscFunctionReturn(PETSC_SUCCESS); 3780e6b6b59SJacob Faibussowitsch if (!dctx->device) { 3790e6b6b59SJacob Faibussowitsch const auto default_dtype = PETSC_DEVICE_DEFAULT(); 3800e6b6b59SJacob Faibussowitsch 3810e6b6b59SJacob 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])); 3820e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextSetDefaultDeviceForType_Internal(dctx, default_dtype)); 3830e6b6b59SJacob Faibussowitsch } 3846a4a1270SPierre Jolivet PetscCall(PetscLogEventBegin(DCONTEXT_SetUp, dctx, nullptr, nullptr, nullptr)); 385dbbe0bcdSBarry Smith PetscUseTypeMethod(dctx, setup); 3866a4a1270SPierre Jolivet PetscCall(PetscLogEventEnd(DCONTEXT_SetUp, dctx, nullptr, nullptr, nullptr)); 387030f984aSJacob Faibussowitsch dctx->setup = PETSC_TRUE; 3883ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 389030f984aSJacob Faibussowitsch } 390030f984aSJacob Faibussowitsch 391d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDeviceContextDuplicate_Private(PetscDeviceContext dctx, PetscStreamType stype, PetscDeviceContext *dctxdup) 392d71ae5a4SJacob Faibussowitsch { 3930e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 3946a4a1270SPierre Jolivet PetscCall(PetscLogEventBegin(DCONTEXT_Duplicate, dctx, nullptr, nullptr, nullptr)); 3950e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextCreate(dctxdup)); 3960e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextSetStreamType(*dctxdup, stype)); 3970e6b6b59SJacob Faibussowitsch if (const auto device = dctx->device) PetscCall(PetscDeviceContextSetDevice_Private(*dctxdup, device, dctx->usersetdevice)); 3980e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextSetUp(*dctxdup)); 3996a4a1270SPierre Jolivet PetscCall(PetscLogEventEnd(DCONTEXT_Duplicate, dctx, nullptr, nullptr, nullptr)); 4003ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 4010e6b6b59SJacob Faibussowitsch } 4020e6b6b59SJacob Faibussowitsch 403*10450e9eSJacob Faibussowitsch // PetscClangLinter pragma disable: -fdoc-section-header-unknown 404030f984aSJacob Faibussowitsch /*@C 405811af0c4SBarry Smith PetscDeviceContextDuplicate - Duplicates a `PetscDeviceContext` object 406030f984aSJacob Faibussowitsch 4070e6b6b59SJacob Faibussowitsch Not Collective 408030f984aSJacob Faibussowitsch 409030f984aSJacob Faibussowitsch Input Parameter: 410811af0c4SBarry Smith . dctx - The `PetscDeviceContext` to duplicate 411030f984aSJacob Faibussowitsch 4126aad120cSJose E. Roman Output Parameter: 413811af0c4SBarry Smith . dctxdup - The duplicated `PetscDeviceContext` 414030f984aSJacob Faibussowitsch 4152fe279fdSBarry Smith Level: beginner 4162fe279fdSBarry Smith 4170e6b6b59SJacob Faibussowitsch Notes: 4180e6b6b59SJacob Faibussowitsch This is a shorthand method for creating a `PetscDeviceContext` with the exact same settings as 4190e6b6b59SJacob Faibussowitsch another. Note however that `dctxdup` does not share any of the underlying data with `dctx`, 4200e6b6b59SJacob Faibussowitsch (including its current stream-state) they are completely separate objects. 4210e6b6b59SJacob Faibussowitsch 4220e6b6b59SJacob Faibussowitsch There is no implied ordering between `dctx` or `dctxdup`. 4230e6b6b59SJacob Faibussowitsch 4240e6b6b59SJacob Faibussowitsch DAG representation: 4250e6b6b59SJacob Faibussowitsch .vb 4260e6b6b59SJacob Faibussowitsch time -> 4270e6b6b59SJacob Faibussowitsch 4280e6b6b59SJacob Faibussowitsch -> dctx - |= CALL =| - dctx ----> 4290e6b6b59SJacob Faibussowitsch - dctxdup -> 4300e6b6b59SJacob Faibussowitsch .ve 431030f984aSJacob Faibussowitsch 4320e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextSetDevice()`, 4330e6b6b59SJacob Faibussowitsch `PetscDeviceContextSetStreamType()` 434030f984aSJacob Faibussowitsch @*/ 435d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextDuplicate(PetscDeviceContext dctx, PetscDeviceContext *dctxdup) 436d71ae5a4SJacob Faibussowitsch { 4370e6b6b59SJacob Faibussowitsch auto stype = PETSC_STREAM_DEFAULT_BLOCKING; 438030f984aSJacob Faibussowitsch 439030f984aSJacob Faibussowitsch PetscFunctionBegin; 4400e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx)); 441030f984aSJacob Faibussowitsch PetscValidPointer(dctxdup, 2); 4420e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetStreamType(dctx, &stype)); 4430e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextDuplicate_Private(dctx, stype, dctxdup)); 4443ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 445030f984aSJacob Faibussowitsch } 446030f984aSJacob Faibussowitsch 447030f984aSJacob Faibussowitsch /*@C 448811af0c4SBarry Smith PetscDeviceContextQueryIdle - Returns whether or not a `PetscDeviceContext` is idle 449030f984aSJacob Faibussowitsch 4500e6b6b59SJacob Faibussowitsch Not Collective 451030f984aSJacob Faibussowitsch 452030f984aSJacob Faibussowitsch Input Parameter: 4530e6b6b59SJacob Faibussowitsch . dctx - The `PetscDeviceContext` 454030f984aSJacob Faibussowitsch 455030f984aSJacob Faibussowitsch Output Parameter: 4560e6b6b59SJacob Faibussowitsch . idle - `PETSC_TRUE` if `dctx` has NO work, `PETSC_FALSE` if it has work 457030f984aSJacob Faibussowitsch 4582fe279fdSBarry Smith Level: intermediate 4592fe279fdSBarry Smith 460811af0c4SBarry Smith Note: 461ef657721SJacob Faibussowitsch This routine only refers a singular context and does NOT take any of its children into 4620e6b6b59SJacob Faibussowitsch account. That is, if `dctx` is idle but has dependents who do have work this routine still 463811af0c4SBarry Smith returns `PETSC_TRUE`. 464030f984aSJacob Faibussowitsch 465db781477SPatrick Sanan .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextWaitForContext()`, `PetscDeviceContextFork()` 466030f984aSJacob Faibussowitsch @*/ 467d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextQueryIdle(PetscDeviceContext dctx, PetscBool *idle) 468d71ae5a4SJacob Faibussowitsch { 469030f984aSJacob Faibussowitsch PetscFunctionBegin; 4700e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx)); 471030f984aSJacob Faibussowitsch PetscValidBoolPointer(idle, 2); 4726a4a1270SPierre Jolivet PetscCall(PetscLogEventBegin(DCONTEXT_QueryIdle, dctx, nullptr, nullptr, nullptr)); 473dbbe0bcdSBarry Smith PetscUseTypeMethod(dctx, query, idle); 4746a4a1270SPierre Jolivet PetscCall(PetscLogEventEnd(DCONTEXT_QueryIdle, dctx, nullptr, nullptr, nullptr)); 4750e6b6b59SJacob 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")); 4763ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 477030f984aSJacob Faibussowitsch } 478030f984aSJacob Faibussowitsch 479*10450e9eSJacob Faibussowitsch // PetscClangLinter pragma disable: -fdoc-section-header-unknown 480030f984aSJacob Faibussowitsch /*@C 481030f984aSJacob Faibussowitsch PetscDeviceContextWaitForContext - Make one context wait for another context to finish 482030f984aSJacob Faibussowitsch 4830e6b6b59SJacob Faibussowitsch Not Collective 484030f984aSJacob Faibussowitsch 485030f984aSJacob Faibussowitsch Input Parameters: 486811af0c4SBarry Smith + dctxa - The `PetscDeviceContext` object that is waiting 487811af0c4SBarry Smith - dctxb - The `PetscDeviceContext` object that is being waited on 488030f984aSJacob Faibussowitsch 4892fe279fdSBarry Smith Level: beginner 4902fe279fdSBarry Smith 491030f984aSJacob Faibussowitsch Notes: 4920e6b6b59SJacob Faibussowitsch Serializes two `PetscDeviceContext`s. Serialization is performed asynchronously; the host 4930e6b6b59SJacob Faibussowitsch does not wait for the serialization to actually occur. 494811af0c4SBarry Smith 4950e6b6b59SJacob Faibussowitsch This routine uses only the state of `dctxb` at the moment this routine was called, so any 4960e6b6b59SJacob Faibussowitsch future work queued will not affect `dctxa`. It is safe to pass the same context to both 4970e6b6b59SJacob Faibussowitsch arguments (in which case this routine does nothing). 4980e6b6b59SJacob Faibussowitsch 4990e6b6b59SJacob Faibussowitsch DAG representation: 5000e6b6b59SJacob Faibussowitsch .vb 5010e6b6b59SJacob Faibussowitsch time -> 5020e6b6b59SJacob Faibussowitsch 5030e6b6b59SJacob Faibussowitsch -> dctxa ---/- |= CALL =| - dctxa -> 5040e6b6b59SJacob Faibussowitsch / 5050e6b6b59SJacob Faibussowitsch -> dctxb -/------------------------> 5060e6b6b59SJacob Faibussowitsch .ve 507030f984aSJacob Faibussowitsch 5080e6b6b59SJacob Faibussowitsch .N ASYNC_API 5090e6b6b59SJacob Faibussowitsch 510db781477SPatrick Sanan .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextQueryIdle()`, `PetscDeviceContextJoin()` 511030f984aSJacob Faibussowitsch @*/ 512d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextWaitForContext(PetscDeviceContext dctxa, PetscDeviceContext dctxb) 513d71ae5a4SJacob Faibussowitsch { 5140e6b6b59SJacob Faibussowitsch PetscObject aobj; 5150e6b6b59SJacob Faibussowitsch 516030f984aSJacob Faibussowitsch PetscFunctionBegin; 5170e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctxa)); 5180e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctxb)); 519030f984aSJacob Faibussowitsch PetscCheckCompatibleDeviceContexts(dctxa, 1, dctxb, 2); 5203ba16761SJacob Faibussowitsch if (dctxa == dctxb) PetscFunctionReturn(PETSC_SUCCESS); 5210e6b6b59SJacob Faibussowitsch aobj = PetscObjectCast(dctxa); 5226a4a1270SPierre Jolivet PetscCall(PetscLogEventBegin(DCONTEXT_WaitForCtx, dctxa, dctxb, nullptr, nullptr)); 523dbbe0bcdSBarry Smith PetscUseTypeMethod(dctxa, waitforcontext, dctxb); 5243398534bSJacob Faibussowitsch PetscCallCXX(CxxDataCast(dctxa)->upstream[dctxb] = CxxDataParent(dctxb)); 5256a4a1270SPierre Jolivet PetscCall(PetscLogEventEnd(DCONTEXT_WaitForCtx, dctxa, dctxb, nullptr, nullptr)); 5260e6b6b59SJacob Faibussowitsch PetscCall(PetscInfo(dctxa, "dctx %" PetscInt64_FMT " waiting on dctx %" PetscInt64_FMT "\n", aobj->id, PetscObjectCast(dctxb)->id)); 5270e6b6b59SJacob Faibussowitsch PetscCall(PetscObjectStateIncrease(aobj)); 5283ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 529030f984aSJacob Faibussowitsch } 530030f984aSJacob Faibussowitsch 531*10450e9eSJacob Faibussowitsch // PetscClangLinter pragma disable: -fdoc-section-header-unknown 5320e6b6b59SJacob Faibussowitsch /*@C 5330e6b6b59SJacob Faibussowitsch PetscDeviceContextForkWithStreamType - Create a set of dependent child contexts from a parent 5340e6b6b59SJacob Faibussowitsch context with a prescribed `PetscStreamType` 5350e6b6b59SJacob Faibussowitsch 5360e6b6b59SJacob Faibussowitsch Not Collective, Asynchronous 5370e6b6b59SJacob Faibussowitsch 5380e6b6b59SJacob Faibussowitsch Input Parameters: 5390e6b6b59SJacob Faibussowitsch + dctx - The parent `PetscDeviceContext` 5400e6b6b59SJacob Faibussowitsch . stype - The prescribed `PetscStreamType` 5410e6b6b59SJacob Faibussowitsch - n - The number of children to create 5420e6b6b59SJacob Faibussowitsch 5430e6b6b59SJacob Faibussowitsch Output Parameter: 5440e6b6b59SJacob Faibussowitsch . dsub - The created child context(s) 5450e6b6b59SJacob Faibussowitsch 5462fe279fdSBarry Smith Level: intermediate 5472fe279fdSBarry Smith 5480e6b6b59SJacob Faibussowitsch Notes: 5490e6b6b59SJacob Faibussowitsch This routine creates `n` edges of a DAG from a source node which are causally dependent on the 5500e6b6b59SJacob Faibussowitsch source node. This causal dependency is established as-if by calling 5510e6b6b59SJacob Faibussowitsch `PetscDeviceContextWaitForContext()` on every child. 5520e6b6b59SJacob Faibussowitsch 5530e6b6b59SJacob Faibussowitsch `dsub` is allocated by this routine and has its lifetime bounded by `dctx`. That is, `dctx` 5540e6b6b59SJacob Faibussowitsch expects to free `dsub` (via `PetscDeviceContextJoin()`) before it itself is destroyed. 5550e6b6b59SJacob Faibussowitsch 5560e6b6b59SJacob Faibussowitsch This routine only accounts for work queued on `dctx` up until calling this routine, any 5570e6b6b59SJacob Faibussowitsch subsequent work enqueued on `dctx` has no effect on `dsub`. 5580e6b6b59SJacob Faibussowitsch 5590e6b6b59SJacob Faibussowitsch The `PetscStreamType` of `dctx` does not have to equal `stype`. In fact, it is often the case 5600e6b6b59SJacob Faibussowitsch that they are different. This is useful in cases where a routine can locally exploit stream 5610e6b6b59SJacob Faibussowitsch parallelism without needing to worry about what stream type the incoming `PetscDeviceContext` 5620e6b6b59SJacob Faibussowitsch carries. 5630e6b6b59SJacob Faibussowitsch 5640e6b6b59SJacob Faibussowitsch DAG representation: 5650e6b6b59SJacob Faibussowitsch .vb 5660e6b6b59SJacob Faibussowitsch time -> 5670e6b6b59SJacob Faibussowitsch 5680e6b6b59SJacob Faibussowitsch -> dctx - |= CALL =| -\----> dctx ------> 5690e6b6b59SJacob Faibussowitsch \---> dsub[0] ---> 5700e6b6b59SJacob Faibussowitsch \--> ... -------> 5710e6b6b59SJacob Faibussowitsch \-> dsub[n-1] -> 5720e6b6b59SJacob Faibussowitsch .ve 5730e6b6b59SJacob Faibussowitsch 5740e6b6b59SJacob Faibussowitsch .N ASYNC_API 5750e6b6b59SJacob Faibussowitsch 5760e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextJoin()`, `PetscDeviceContextSynchronize()`, 5770e6b6b59SJacob Faibussowitsch `PetscDeviceContextQueryIdle()`, `PetscDeviceContextWaitForContext()` 5780e6b6b59SJacob Faibussowitsch @*/ 579d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextForkWithStreamType(PetscDeviceContext dctx, PetscStreamType stype, PetscInt n, PetscDeviceContext **dsub) 580d71ae5a4SJacob Faibussowitsch { 5810e6b6b59SJacob Faibussowitsch // debugging only 5820e6b6b59SJacob Faibussowitsch std::string idList; 5830e6b6b59SJacob Faibussowitsch auto ninput = n; 5840e6b6b59SJacob Faibussowitsch 5850e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 5860e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx)); 5870e6b6b59SJacob Faibussowitsch PetscAssert(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of contexts requested %" PetscInt_FMT " < 0", n); 5880e6b6b59SJacob Faibussowitsch PetscValidPointer(dsub, 4); 5890e6b6b59SJacob Faibussowitsch *dsub = nullptr; 5900e6b6b59SJacob Faibussowitsch /* reserve 4 chars per id, 2 for number and 2 for ', ' separator */ 5910e6b6b59SJacob Faibussowitsch if (PetscDefined(USE_DEBUG_AND_INFO)) PetscCallCXX(idList.reserve(4 * n)); 5926a4a1270SPierre Jolivet PetscCall(PetscLogEventBegin(DCONTEXT_Fork, dctx, nullptr, nullptr, nullptr)); 5930e6b6b59SJacob Faibussowitsch /* update child totals */ 5940e6b6b59SJacob Faibussowitsch dctx->numChildren += n; 5950e6b6b59SJacob Faibussowitsch /* now to find out if we have room */ 5960e6b6b59SJacob Faibussowitsch if (dctx->numChildren > dctx->maxNumChildren) { 5970e6b6b59SJacob Faibussowitsch const auto numChildren = dctx->numChildren; 5980e6b6b59SJacob Faibussowitsch auto &maxNumChildren = dctx->maxNumChildren; 5990e6b6b59SJacob Faibussowitsch auto numAllocated = numChildren; 6000e6b6b59SJacob Faibussowitsch 6010e6b6b59SJacob Faibussowitsch /* no room, either from having too many kids or not having any */ 6020e6b6b59SJacob Faibussowitsch if (auto &childIDs = dctx->childIDs) { 6030e6b6b59SJacob Faibussowitsch // the difference is backwards because we have not updated maxNumChildren yet 6040e6b6b59SJacob Faibussowitsch numAllocated -= maxNumChildren; 6050e6b6b59SJacob Faibussowitsch /* have existing children, must reallocate them */ 6060e6b6b59SJacob Faibussowitsch PetscCall(PetscRealloc(numChildren * sizeof(*childIDs), &childIDs)); 6070e6b6b59SJacob Faibussowitsch /* clear the extra memory since realloc doesn't do it for us */ 6080e6b6b59SJacob Faibussowitsch PetscCall(PetscArrayzero(std::next(childIDs, maxNumChildren), numAllocated)); 6090e6b6b59SJacob Faibussowitsch } else { 6100e6b6b59SJacob Faibussowitsch /* have no children */ 6110e6b6b59SJacob Faibussowitsch PetscCall(PetscCalloc1(numChildren, &childIDs)); 6120e6b6b59SJacob Faibussowitsch } 6130e6b6b59SJacob Faibussowitsch /* update total number of children */ 6140e6b6b59SJacob Faibussowitsch maxNumChildren = numChildren; 6150e6b6b59SJacob Faibussowitsch } 6160e6b6b59SJacob Faibussowitsch PetscCall(PetscMalloc1(n, dsub)); 6170e6b6b59SJacob Faibussowitsch for (PetscInt i = 0; ninput && (i < dctx->numChildren); ++i) { 6180e6b6b59SJacob Faibussowitsch auto &childID = dctx->childIDs[i]; 6190e6b6b59SJacob Faibussowitsch /* empty child slot */ 6200e6b6b59SJacob Faibussowitsch if (!childID) { 6210e6b6b59SJacob Faibussowitsch auto &childctx = (*dsub)[i]; 6220e6b6b59SJacob Faibussowitsch 6230e6b6b59SJacob Faibussowitsch /* create the child context in the image of its parent */ 6240e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextDuplicate_Private(dctx, stype, &childctx)); 6250e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextWaitForContext(childctx, dctx)); 6260e6b6b59SJacob Faibussowitsch /* register the child with its parent */ 6270e6b6b59SJacob Faibussowitsch PetscCall(PetscObjectGetId(PetscObjectCast(childctx), &childID)); 6280e6b6b59SJacob Faibussowitsch if (PetscDefined(USE_DEBUG_AND_INFO)) { 6290e6b6b59SJacob Faibussowitsch PetscCallCXX(idList += std::to_string(childID)); 6300e6b6b59SJacob Faibussowitsch if (ninput != 1) PetscCallCXX(idList += ", "); 6310e6b6b59SJacob Faibussowitsch } 6320e6b6b59SJacob Faibussowitsch --ninput; 6330e6b6b59SJacob Faibussowitsch } 6340e6b6b59SJacob Faibussowitsch } 6356a4a1270SPierre Jolivet PetscCall(PetscLogEventEnd(DCONTEXT_Fork, dctx, nullptr, nullptr, nullptr)); 6360e6b6b59SJacob Faibussowitsch PetscCall(PetscDebugInfo(dctx, "Forked %" PetscInt_FMT " children from parent %" PetscInt64_FMT " with IDs: %s\n", n, PetscObjectCast(dctx)->id, idList.c_str())); 6373ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 6380e6b6b59SJacob Faibussowitsch } 6390e6b6b59SJacob Faibussowitsch 640030f984aSJacob Faibussowitsch /*@C 641030f984aSJacob Faibussowitsch PetscDeviceContextFork - Create a set of dependent child contexts from a parent context 642030f984aSJacob Faibussowitsch 643030f984aSJacob Faibussowitsch Not Collective, Asynchronous 644030f984aSJacob Faibussowitsch 645030f984aSJacob Faibussowitsch Input Parameters: 646811af0c4SBarry Smith + dctx - The parent `PetscDeviceContext` 647030f984aSJacob Faibussowitsch - n - The number of children to create 648030f984aSJacob Faibussowitsch 649030f984aSJacob Faibussowitsch Output Parameter: 650030f984aSJacob Faibussowitsch . dsub - The created child context(s) 651030f984aSJacob Faibussowitsch 6522fe279fdSBarry Smith Level: beginner 6532fe279fdSBarry Smith 654030f984aSJacob Faibussowitsch Notes: 6550e6b6b59SJacob Faibussowitsch Behaves identically to `PetscDeviceContextForkWithStreamType()` except that the prescribed 6560e6b6b59SJacob Faibussowitsch `PetscStreamType` is taken from `dctx`. In effect this routine is shorthand for\: 657030f984aSJacob Faibussowitsch 658030f984aSJacob Faibussowitsch .vb 6590e6b6b59SJacob Faibussowitsch PetscStreamType stype; 660030f984aSJacob Faibussowitsch 6610e6b6b59SJacob Faibussowitsch PetscDeviceContextGetStreamType(dctx, &stype); 6620e6b6b59SJacob Faibussowitsch PetscDeviceContextForkWithStreamType(dctx, stype, ...); 663030f984aSJacob Faibussowitsch .ve 664030f984aSJacob Faibussowitsch 6650e6b6b59SJacob Faibussowitsch .N ASYNC_API 6660e6b6b59SJacob Faibussowitsch 6670e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextForkWithStreamType()`, `PetscDeviceContextJoin()`, 6680e6b6b59SJacob Faibussowitsch `PetscDeviceContextSynchronize()`, `PetscDeviceContextQueryIdle()` 669030f984aSJacob Faibussowitsch @*/ 670d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextFork(PetscDeviceContext dctx, PetscInt n, PetscDeviceContext **dsub) 671d71ae5a4SJacob Faibussowitsch { 6720e6b6b59SJacob Faibussowitsch auto stype = PETSC_STREAM_DEFAULT_BLOCKING; 673030f984aSJacob Faibussowitsch 674030f984aSJacob Faibussowitsch PetscFunctionBegin; 6750e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx)); 6760e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetStreamType(dctx, &stype)); 6770e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextForkWithStreamType(dctx, stype, n, dsub)); 6783ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 679030f984aSJacob Faibussowitsch } 680030f984aSJacob Faibussowitsch 681*10450e9eSJacob Faibussowitsch // PetscClangLinter pragma disable: -fdoc-section-header-unknown 682030f984aSJacob Faibussowitsch /*@C 6835181c4f9SJacob Faibussowitsch PetscDeviceContextJoin - Converge a set of child contexts 684030f984aSJacob Faibussowitsch 685030f984aSJacob Faibussowitsch Not Collective, Asynchronous 686030f984aSJacob Faibussowitsch 687030f984aSJacob Faibussowitsch Input Parameters: 688811af0c4SBarry Smith + dctx - A `PetscDeviceContext` to converge on 689030f984aSJacob Faibussowitsch . n - The number of sub contexts to converge 690030f984aSJacob Faibussowitsch . joinMode - The type of join to perform 691030f984aSJacob Faibussowitsch - dsub - The sub contexts to converge 692030f984aSJacob Faibussowitsch 6932fe279fdSBarry Smith Level: beginner 6942fe279fdSBarry Smith 695030f984aSJacob Faibussowitsch Notes: 6960e6b6b59SJacob Faibussowitsch If `PetscDeviceContextFork()` creates `n` edges from a source node which all depend on the source 6970e6b6b59SJacob Faibussowitsch node, then this routine is the exact mirror. That is, it creates a node (represented in `dctx`) 69835cb6cd3SPierre Jolivet which receives `n` edges (and optionally destroys them) which is dependent on the completion 6990e6b6b59SJacob Faibussowitsch of all incoming edges. 700030f984aSJacob Faibussowitsch 7010e6b6b59SJacob Faibussowitsch If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_DESTROY`. All contexts in `dsub` will be 7020e6b6b59SJacob Faibussowitsch destroyed by this routine. Thus all sub contexts must have been created with the `dctx` 7030e6b6b59SJacob Faibussowitsch passed to this routine. 704030f984aSJacob Faibussowitsch 7050e6b6b59SJacob Faibussowitsch If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_SYNC`. All sub contexts will additionally wait on 7060e6b6b59SJacob Faibussowitsch `dctx` after converging. This has the effect of "synchronizing" the outgoing edges. Note the 7070e6b6b59SJacob Faibussowitsch sync suffix does NOT refer to the host, i.e. this routine does NOT call 7080e6b6b59SJacob Faibussowitsch `PetscDeviceSynchronize()`. 709030f984aSJacob Faibussowitsch 7100e6b6b59SJacob Faibussowitsch If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC`. `dctx` waits for all sub contexts but 7110e6b6b59SJacob Faibussowitsch the sub contexts do not wait for one another or `dctx` afterwards. 712030f984aSJacob Faibussowitsch 713030f984aSJacob Faibussowitsch DAG representations: 714811af0c4SBarry Smith If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_DESTROY` 715030f984aSJacob Faibussowitsch .vb 716030f984aSJacob Faibussowitsch time -> 717030f984aSJacob Faibussowitsch 7180e6b6b59SJacob Faibussowitsch -> dctx ---------/- |= CALL =| - dctx -> 719030f984aSJacob Faibussowitsch -> dsub[0] -----/ 720030f984aSJacob Faibussowitsch -> ... -------/ 721030f984aSJacob Faibussowitsch -> dsub[n-1] -/ 722030f984aSJacob Faibussowitsch .ve 723811af0c4SBarry Smith If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_SYNC` 724030f984aSJacob Faibussowitsch .vb 725030f984aSJacob Faibussowitsch time -> 726030f984aSJacob Faibussowitsch 7270e6b6b59SJacob Faibussowitsch -> dctx ---------/- |= CALL =| -\----> dctx ------> 728030f984aSJacob Faibussowitsch -> dsub[0] -----/ \---> dsub[0] ---> 729030f984aSJacob Faibussowitsch -> ... -------/ \--> ... -------> 730030f984aSJacob Faibussowitsch -> dsub[n-1] -/ \-> dsub[n-1] -> 731030f984aSJacob Faibussowitsch .ve 7320e6b6b59SJacob Faibussowitsch If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC` 7330e6b6b59SJacob Faibussowitsch .vb 7340e6b6b59SJacob Faibussowitsch time -> 735030f984aSJacob Faibussowitsch 7360e6b6b59SJacob Faibussowitsch -> dctx ----------/- |= CALL =| - dctx -> 7370e6b6b59SJacob Faibussowitsch -> dsub[0] ------/-----------------------> 7380e6b6b59SJacob Faibussowitsch -> ... --------/------------------------> 7390e6b6b59SJacob Faibussowitsch -> dsub[n-1] --/-------------------------> 7400e6b6b59SJacob Faibussowitsch .ve 741030f984aSJacob Faibussowitsch 7420e6b6b59SJacob Faibussowitsch .N ASYNC_API 7430e6b6b59SJacob Faibussowitsch 7440e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextFork()`, `PetscDeviceContextForkWithStreamType()`, 7450e6b6b59SJacob Faibussowitsch `PetscDeviceContextSynchronize()`, `PetscDeviceContextJoinMode` 746030f984aSJacob Faibussowitsch @*/ 747d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextJoin(PetscDeviceContext dctx, PetscInt n, PetscDeviceContextJoinMode joinMode, PetscDeviceContext **dsub) 748d71ae5a4SJacob Faibussowitsch { 7490e6b6b59SJacob Faibussowitsch // debugging only 7500e6b6b59SJacob Faibussowitsch std::string idList; 751030f984aSJacob Faibussowitsch 752030f984aSJacob Faibussowitsch PetscFunctionBegin; 7530e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx)); 754030f984aSJacob Faibussowitsch /* validity of dctx is checked in the wait-for loop */ 755030f984aSJacob Faibussowitsch PetscValidPointer(dsub, 4); 756bf025ffbSJacob Faibussowitsch PetscAssert(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of contexts merged %" PetscInt_FMT " < 0", n); 757030f984aSJacob Faibussowitsch /* reserve 4 chars per id, 2 for number and 2 for ', ' separator */ 7580e6b6b59SJacob Faibussowitsch if (PetscDefined(USE_DEBUG_AND_INFO)) PetscCallCXX(idList.reserve(4 * n)); 759030f984aSJacob Faibussowitsch /* first dctx waits on all the incoming edges */ 7606a4a1270SPierre Jolivet PetscCall(PetscLogEventBegin(DCONTEXT_Join, dctx, nullptr, nullptr, nullptr)); 761030f984aSJacob Faibussowitsch for (PetscInt i = 0; i < n; ++i) { 762030f984aSJacob Faibussowitsch PetscCheckCompatibleDeviceContexts(dctx, 1, (*dsub)[i], 4); 7639566063dSJacob Faibussowitsch PetscCall(PetscDeviceContextWaitForContext(dctx, (*dsub)[i])); 7640e6b6b59SJacob Faibussowitsch if (PetscDefined(USE_DEBUG_AND_INFO)) { 7650e6b6b59SJacob Faibussowitsch PetscCallCXX(idList += std::to_string(PetscObjectCast((*dsub)[i])->id)); 7660e6b6b59SJacob Faibussowitsch if (i + 1 < n) PetscCallCXX(idList += ", "); 7670e6b6b59SJacob Faibussowitsch } 768030f984aSJacob Faibussowitsch } 769030f984aSJacob Faibussowitsch 770030f984aSJacob Faibussowitsch /* now we handle the aftermath */ 771030f984aSJacob Faibussowitsch switch (joinMode) { 7729371c9d4SSatish Balay case PETSC_DEVICE_CONTEXT_JOIN_DESTROY: { 7730e6b6b59SJacob Faibussowitsch const auto children = dctx->childIDs; 7740e6b6b59SJacob Faibussowitsch const auto maxchild = dctx->maxNumChildren; 7750e6b6b59SJacob Faibussowitsch auto &nchild = dctx->numChildren; 776030f984aSJacob Faibussowitsch PetscInt j = 0; 777030f984aSJacob Faibussowitsch 7780e6b6b59SJacob 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); 779030f984aSJacob Faibussowitsch /* update child count while it's still fresh in memory */ 7800e6b6b59SJacob Faibussowitsch nchild -= n; 7810e6b6b59SJacob Faibussowitsch for (PetscInt i = 0; i < maxchild; ++i) { 7820e6b6b59SJacob Faibussowitsch if (children[i] && (children[i] == PetscObjectCast((*dsub)[j])->id)) { 783030f984aSJacob Faibussowitsch /* child is one of ours, can destroy it */ 7849566063dSJacob Faibussowitsch PetscCall(PetscDeviceContextDestroy((*dsub) + j)); 785030f984aSJacob Faibussowitsch /* reset the child slot */ 7860e6b6b59SJacob Faibussowitsch children[i] = 0; 787030f984aSJacob Faibussowitsch if (++j == n) break; 788030f984aSJacob Faibussowitsch } 789030f984aSJacob Faibussowitsch } 7900e6b6b59SJacob Faibussowitsch /* gone through the loop but did not find every child */ 7910e6b6b59SJacob 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); 7929566063dSJacob Faibussowitsch PetscCall(PetscFree(*dsub)); 7939371c9d4SSatish Balay } break; 794030f984aSJacob Faibussowitsch case PETSC_DEVICE_CONTEXT_JOIN_SYNC: 7959566063dSJacob Faibussowitsch for (PetscInt i = 0; i < n; ++i) PetscCall(PetscDeviceContextWaitForContext((*dsub)[i], dctx)); 796d71ae5a4SJacob Faibussowitsch case PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC: 797d71ae5a4SJacob Faibussowitsch break; 798d71ae5a4SJacob Faibussowitsch default: 799d71ae5a4SJacob Faibussowitsch SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown PetscDeviceContextJoinMode given"); 800030f984aSJacob Faibussowitsch } 8016a4a1270SPierre Jolivet PetscCall(PetscLogEventEnd(DCONTEXT_Join, dctx, nullptr, nullptr, nullptr)); 802030f984aSJacob Faibussowitsch 8030e6b6b59SJacob 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())); 8043ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 805030f984aSJacob Faibussowitsch } 806030f984aSJacob Faibussowitsch 807*10450e9eSJacob Faibussowitsch // PetscClangLinter pragma disable: -fdoc-section-header-unknown 808030f984aSJacob Faibussowitsch /*@C 8090e6b6b59SJacob Faibussowitsch PetscDeviceContextSynchronize - Block the host until all work queued on a 8100e6b6b59SJacob Faibussowitsch `PetscDeviceContext` has finished 811030f984aSJacob Faibussowitsch 8120e6b6b59SJacob Faibussowitsch Not Collective 813030f984aSJacob Faibussowitsch 8142fe279fdSBarry Smith Input Parameter: 815811af0c4SBarry Smith . dctx - The `PetscDeviceContext` to synchronize 816030f984aSJacob Faibussowitsch 8172fe279fdSBarry Smith Level: beginner 8182fe279fdSBarry Smith 8190e6b6b59SJacob Faibussowitsch Notes: 8200e6b6b59SJacob Faibussowitsch The host will not return from this routine until `dctx` is idle. Any and all memory 8210e6b6b59SJacob Faibussowitsch operations queued on or otherwise associated with (either explicitly or implicitly via 8220e6b6b59SJacob Faibussowitsch dependencies) are guaranteed to have finished and be globally visible on return. 8230e6b6b59SJacob Faibussowitsch 8240e6b6b59SJacob Faibussowitsch In effect, this routine serves as memory and execution barrier. 8250e6b6b59SJacob Faibussowitsch 8260e6b6b59SJacob Faibussowitsch DAG representation: 8270e6b6b59SJacob Faibussowitsch .vb 8280e6b6b59SJacob Faibussowitsch time -> 8290e6b6b59SJacob Faibussowitsch 8300e6b6b59SJacob Faibussowitsch -> dctx - |= CALL =| - dctx -> 8310e6b6b59SJacob Faibussowitsch .ve 8320e6b6b59SJacob Faibussowitsch 833db781477SPatrick Sanan .seealso: `PetscDeviceContextFork()`, `PetscDeviceContextJoin()`, `PetscDeviceContextQueryIdle()` 834030f984aSJacob Faibussowitsch @*/ 835d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextSynchronize(PetscDeviceContext dctx) 836d71ae5a4SJacob Faibussowitsch { 837030f984aSJacob Faibussowitsch PetscFunctionBegin; 8380e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx)); 8396a4a1270SPierre Jolivet PetscCall(PetscLogEventBegin(DCONTEXT_Sync, dctx, nullptr, nullptr, nullptr)); 840030f984aSJacob Faibussowitsch /* if it isn't setup there is nothing to sync on */ 8410e6b6b59SJacob Faibussowitsch if (dctx->setup) { 8422f85e401SJacob Faibussowitsch PetscUseTypeMethod(dctx, synchronize); 8430e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextSyncClearMap_Internal(dctx)); 8440e6b6b59SJacob Faibussowitsch } 8456a4a1270SPierre Jolivet PetscCall(PetscLogEventEnd(DCONTEXT_Sync, dctx, nullptr, nullptr, nullptr)); 8463ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 847030f984aSJacob Faibussowitsch } 848030f984aSJacob Faibussowitsch 8490e6b6b59SJacob Faibussowitsch /* every device type has a vector of null PetscDeviceContexts -- one for each device */ 8500e6b6b59SJacob Faibussowitsch static auto nullContexts = std::array<std::vector<PetscDeviceContext>, PETSC_DEVICE_MAX>{}; 8510e6b6b59SJacob Faibussowitsch static auto nullContextsFinalizer = false; 852030f984aSJacob Faibussowitsch 853d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDeviceContextGetNullContextForDevice_Private(PetscBool user_set_device, PetscDevice device, PetscDeviceContext *dctx) 854d71ae5a4SJacob Faibussowitsch { 8550e6b6b59SJacob Faibussowitsch PetscInt devid; 8560e6b6b59SJacob Faibussowitsch PetscDeviceType dtype; 857a4af0ceeSJacob Faibussowitsch 858030f984aSJacob Faibussowitsch PetscFunctionBegin; 8590e6b6b59SJacob Faibussowitsch PetscValidDevice(device, 2); 8600e6b6b59SJacob Faibussowitsch PetscValidPointer(dctx, 3); 8610e6b6b59SJacob Faibussowitsch if (PetscUnlikely(!nullContextsFinalizer)) { 8620e6b6b59SJacob Faibussowitsch const auto finalizer = [] { 8630e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 8640e6b6b59SJacob Faibussowitsch for (auto &&dvec : nullContexts) { 8650e6b6b59SJacob Faibussowitsch for (auto &&dctx : dvec) PetscCall(PetscDeviceContextDestroy(&dctx)); 8660e6b6b59SJacob Faibussowitsch PetscCallCXX(dvec.clear()); 867030f984aSJacob Faibussowitsch } 8680e6b6b59SJacob Faibussowitsch nullContextsFinalizer = false; 8693ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 870a4af0ceeSJacob Faibussowitsch }; 871a4af0ceeSJacob Faibussowitsch 8720e6b6b59SJacob Faibussowitsch nullContextsFinalizer = true; 8730e6b6b59SJacob Faibussowitsch PetscCall(PetscRegisterFinalize(std::move(finalizer))); 8740e6b6b59SJacob Faibussowitsch } 8750e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceGetDeviceId(device, &devid)); 8760e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceGetType(device, &dtype)); 8770e6b6b59SJacob Faibussowitsch { 8780e6b6b59SJacob Faibussowitsch auto &ctxlist = nullContexts[dtype]; 8790e6b6b59SJacob Faibussowitsch 8800e6b6b59SJacob Faibussowitsch PetscCheck(devid >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Device ID (%" PetscInt_FMT ") must be positive", devid); 8810e6b6b59SJacob Faibussowitsch // need to resize the container if not big enough because incrementing the iterator in 8820e6b6b59SJacob Faibussowitsch // std::next() (if we haven't initialized that ctx yet) may cause it to fall outside the 8830e6b6b59SJacob Faibussowitsch // current size of the container. 8840e6b6b59SJacob Faibussowitsch if (static_cast<std::size_t>(devid) >= ctxlist.size()) PetscCallCXX(ctxlist.resize(devid + 1)); 8850e6b6b59SJacob Faibussowitsch if (PetscUnlikely(!ctxlist[devid])) { 8860e6b6b59SJacob Faibussowitsch // we have not seen this device before 8870e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextCreate(dctx)); 888403f9ca4SJacob Faibussowitsch PetscCall(PetscInfo(*dctx, "Initializing null PetscDeviceContext (of type %s) for device %" PetscInt_FMT "\n", PetscDeviceTypes[dtype], devid)); 8890e6b6b59SJacob Faibussowitsch { 8900e6b6b59SJacob Faibussowitsch const auto pobj = PetscObjectCast(*dctx); 8910e6b6b59SJacob Faibussowitsch const auto name = "null context " + std::to_string(devid); 8920e6b6b59SJacob Faibussowitsch const auto prefix = "null_context_" + std::to_string(devid) + '_'; 8930e6b6b59SJacob Faibussowitsch 8940e6b6b59SJacob Faibussowitsch PetscCall(PetscObjectSetName(pobj, name.c_str())); 8950e6b6b59SJacob Faibussowitsch PetscCall(PetscObjectSetOptionsPrefix(pobj, prefix.c_str())); 8960e6b6b59SJacob Faibussowitsch } 8970e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextSetStreamType(*dctx, PETSC_STREAM_GLOBAL_BLOCKING)); 8980e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextSetDevice_Private(*dctx, device, user_set_device)); 8990e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextSetUp(*dctx)); 9000e6b6b59SJacob Faibussowitsch // would use ctxlist.cbegin() but GCC 4.8 can't handle const iterator insert! 9010e6b6b59SJacob Faibussowitsch PetscCallCXX(ctxlist.insert(std::next(ctxlist.begin(), devid), *dctx)); 9020e6b6b59SJacob Faibussowitsch } else *dctx = ctxlist[devid]; 9030e6b6b59SJacob Faibussowitsch } 9043ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 905030f984aSJacob Faibussowitsch } 906030f984aSJacob Faibussowitsch 9070e6b6b59SJacob Faibussowitsch /* 9080e6b6b59SJacob Faibussowitsch Gets the "NULL" context for the current PetscDeviceType and PetscDevice. NULL contexts are 9090e6b6b59SJacob Faibussowitsch guaranteed to always be globally blocking. 9100e6b6b59SJacob Faibussowitsch */ 911d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextGetNullContext_Internal(PetscDeviceContext *dctx) 912d71ae5a4SJacob Faibussowitsch { 9130e6b6b59SJacob Faibussowitsch PetscDeviceContext gctx; 9140e6b6b59SJacob Faibussowitsch PetscDevice gdev = nullptr; 915030f984aSJacob Faibussowitsch 916a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 917a4af0ceeSJacob Faibussowitsch PetscValidPointer(dctx, 1); 9180e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetCurrentContext(&gctx)); 9190e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetDevice(gctx, &gdev)); 9200e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetNullContextForDevice_Private(gctx->usersetdevice, gdev, dctx)); 9213ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 922030f984aSJacob Faibussowitsch } 923030f984aSJacob Faibussowitsch 924030f984aSJacob Faibussowitsch /*@C 925811af0c4SBarry Smith PetscDeviceContextSetFromOptions - Configure a `PetscDeviceContext` from the options database 926030f984aSJacob Faibussowitsch 9270e6b6b59SJacob Faibussowitsch Collective on `comm` or `dctx` 928030f984aSJacob Faibussowitsch 929030f984aSJacob Faibussowitsch Input Parameters: 9300e6b6b59SJacob Faibussowitsch + comm - MPI communicator on which to query the options database (optional) 931811af0c4SBarry Smith - dctx - The `PetscDeviceContext` to configure 932030f984aSJacob Faibussowitsch 933030f984aSJacob Faibussowitsch Output Parameter: 934811af0c4SBarry Smith . dctx - The `PetscDeviceContext` 935030f984aSJacob Faibussowitsch 9363c7db156SBarry Smith Options Database Keys: 9370e6b6b59SJacob Faibussowitsch + -device_context_stream_type - type of stream to create inside the `PetscDeviceContext` - 9380e6b6b59SJacob Faibussowitsch `PetscDeviceContextSetStreamType()` 939811af0c4SBarry Smith - -device_context_device_type - the type of `PetscDevice` to attach by default - `PetscDeviceType` 940030f984aSJacob Faibussowitsch 9412fe279fdSBarry Smith Level: beginner 9422fe279fdSBarry Smith 9432fe279fdSBarry Smith Note: 9440e6b6b59SJacob Faibussowitsch The user may pass `MPI_COMM_NULL` for `comm` in which case the communicator of `dctx` is 9450e6b6b59SJacob Faibussowitsch used (which is always `PETSC_COMM_SELF`). 9460e6b6b59SJacob Faibussowitsch 9470e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextSetStreamType()`, `PetscDeviceContextSetDevice()`, 9480e6b6b59SJacob Faibussowitsch `PetscDeviceContextView()` 949030f984aSJacob Faibussowitsch @*/ 950d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetFromOptions(MPI_Comm comm, PetscDeviceContext dctx) 951d71ae5a4SJacob Faibussowitsch { 9520e6b6b59SJacob Faibussowitsch const auto pobj = PetscObjectCast(dctx); 9530e6b6b59SJacob Faibussowitsch auto dtype = std::make_pair(PETSC_DEVICE_DEFAULT(), PETSC_FALSE); 9540e6b6b59SJacob Faibussowitsch auto stype = std::make_pair(PETSC_DEVICE_CONTEXT_DEFAULT_STREAM_TYPE, PETSC_FALSE); 955e6b8bd2aSJacob Faibussowitsch MPI_Comm old_comm = PETSC_COMM_SELF; 956030f984aSJacob Faibussowitsch 957030f984aSJacob Faibussowitsch PetscFunctionBegin; 9580e6b6b59SJacob Faibussowitsch // do not user getoptionalnullcontext here, the user is not allowed to set it from options! 9590e6b6b59SJacob Faibussowitsch PetscValidDeviceContext(dctx, 2); 9600e6b6b59SJacob Faibussowitsch /* set the device type first */ 9610e6b6b59SJacob Faibussowitsch if (const auto device = dctx->device) PetscCall(PetscDeviceGetType(device, &dtype.first)); 9620e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetStreamType(dctx, &stype.first)); 9630e6b6b59SJacob Faibussowitsch 9640e6b6b59SJacob Faibussowitsch if (comm == MPI_COMM_NULL) { 9650e6b6b59SJacob Faibussowitsch PetscCall(PetscObjectGetComm(pobj, &comm)); 9660e6b6b59SJacob Faibussowitsch } else { 9670e6b6b59SJacob Faibussowitsch // briefly set the communicator for dctx (it is always PETSC_COMM_SELF) so 9680e6b6b59SJacob Faibussowitsch // PetscObjectOptionsBegin() behaves as if dctx had comm 9690e6b6b59SJacob Faibussowitsch old_comm = Petsc::util::exchange(pobj->comm, comm); 9700e6b6b59SJacob Faibussowitsch } 9710e6b6b59SJacob Faibussowitsch 9720e6b6b59SJacob Faibussowitsch PetscObjectOptionsBegin(pobj); 9730e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextQueryOptions_Internal(PetscOptionsObject, dtype, stype)); 974d0609cedSBarry Smith PetscOptionsEnd(); 9750e6b6b59SJacob Faibussowitsch // reset the comm (should be PETSC_COMM_SELF) 9760e6b6b59SJacob Faibussowitsch if (comm != MPI_COMM_NULL) pobj->comm = old_comm; 9770e6b6b59SJacob Faibussowitsch if (dtype.second) PetscCall(PetscDeviceContextSetDefaultDeviceForType_Internal(dctx, dtype.first)); 9780e6b6b59SJacob Faibussowitsch if (stype.second) PetscCall(PetscDeviceContextSetStreamType(dctx, stype.first)); 9790e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextSetUp(dctx)); 9803ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 9810e6b6b59SJacob Faibussowitsch } 9820e6b6b59SJacob Faibussowitsch 9830e6b6b59SJacob Faibussowitsch /*@C 9840e6b6b59SJacob Faibussowitsch PetscDeviceContextView - View a `PetscDeviceContext` 9850e6b6b59SJacob Faibussowitsch 9860e6b6b59SJacob Faibussowitsch Collective on `viewer` 9870e6b6b59SJacob Faibussowitsch 9880e6b6b59SJacob Faibussowitsch Input Parameters: 9890e6b6b59SJacob Faibussowitsch + dctx - The `PetscDeviceContext` 9900e6b6b59SJacob Faibussowitsch - viewer - The `PetscViewer` to view `dctx` with (may be `NULL`) 9910e6b6b59SJacob Faibussowitsch 9922fe279fdSBarry Smith Level: beginner 9932fe279fdSBarry Smith 9942fe279fdSBarry Smith Note: 9950e6b6b59SJacob Faibussowitsch If `viewer` is `NULL`, `PETSC_VIEWER_STDOUT_WORLD` is used instead, in which case this 9960e6b6b59SJacob Faibussowitsch routine is collective on `PETSC_COMM_WORLD`. 9970e6b6b59SJacob Faibussowitsch 9980e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextViewFromOptions()`, `PetscDeviceView()`, `PETSC_VIEWER_STDOUT_WORLD`, `PetscDeviceContextCreate()` 9990e6b6b59SJacob Faibussowitsch @*/ 1000d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextView(PetscDeviceContext dctx, PetscViewer viewer) 1001d71ae5a4SJacob Faibussowitsch { 10020e6b6b59SJacob Faibussowitsch PetscBool iascii; 10030e6b6b59SJacob Faibussowitsch 10040e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 10050e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx)); 10060e6b6b59SJacob Faibussowitsch if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PETSC_COMM_WORLD, &viewer)); 10070e6b6b59SJacob Faibussowitsch PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 10080e6b6b59SJacob Faibussowitsch PetscCall(PetscObjectTypeCompare(PetscObjectCast(viewer), PETSCVIEWERASCII, &iascii)); 10090e6b6b59SJacob Faibussowitsch if (iascii) { 10100e6b6b59SJacob Faibussowitsch auto stype = PETSC_STREAM_DEFAULT_BLOCKING; 10110e6b6b59SJacob Faibussowitsch PetscViewer sub; 10120e6b6b59SJacob Faibussowitsch 10130e6b6b59SJacob Faibussowitsch PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sub)); 10140e6b6b59SJacob Faibussowitsch PetscCall(PetscObjectPrintClassNamePrefixType(PetscObjectCast(dctx), sub)); 10150e6b6b59SJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(sub)); 10160e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetStreamType(dctx, &stype)); 10170e6b6b59SJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(sub, "stream type: %s\n", PetscStreamTypes[stype])); 10180e6b6b59SJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(sub, "children: %" PetscInt_FMT "\n", dctx->numChildren)); 10190e6b6b59SJacob Faibussowitsch if (const auto nchild = dctx->numChildren) { 10200e6b6b59SJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(sub)); 10210e6b6b59SJacob Faibussowitsch for (PetscInt i = 0; i < nchild; ++i) { 10220e6b6b59SJacob Faibussowitsch if (i == nchild - 1) { 10230e6b6b59SJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(sub, "%" PetscInt64_FMT, dctx->childIDs[i])); 10240e6b6b59SJacob Faibussowitsch } else { 10250e6b6b59SJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(sub, "%" PetscInt64_FMT ", ", dctx->childIDs[i])); 10260e6b6b59SJacob Faibussowitsch } 10270e6b6b59SJacob Faibussowitsch } 10280e6b6b59SJacob Faibussowitsch } 10290e6b6b59SJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(sub)); 10300e6b6b59SJacob Faibussowitsch PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sub)); 10310e6b6b59SJacob Faibussowitsch PetscCall(PetscViewerFlush(viewer)); 10320e6b6b59SJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer)); 10330e6b6b59SJacob Faibussowitsch } 10340e6b6b59SJacob Faibussowitsch if (const auto device = dctx->device) PetscCall(PetscDeviceView(device, viewer)); 10350e6b6b59SJacob Faibussowitsch if (iascii) PetscCall(PetscViewerASCIIPopTab(viewer)); 10363ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 10370e6b6b59SJacob Faibussowitsch } 10380e6b6b59SJacob Faibussowitsch 10390e6b6b59SJacob Faibussowitsch /*@C 10400e6b6b59SJacob Faibussowitsch PetscDeviceContextViewFromOptions - View a `PetscDeviceContext` from options 10410e6b6b59SJacob Faibussowitsch 10420e6b6b59SJacob Faibussowitsch Input Parameters: 10430e6b6b59SJacob Faibussowitsch + dctx - The `PetscDeviceContext` to view 10440e6b6b59SJacob Faibussowitsch . obj - Optional `PetscObject` to associate (may be `NULL`) 10450e6b6b59SJacob Faibussowitsch - name - The command line option 10460e6b6b59SJacob Faibussowitsch 10470e6b6b59SJacob Faibussowitsch Level: beginner 10480e6b6b59SJacob Faibussowitsch 10490e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextView()`, `PetscObjectViewFromOptions()`, `PetscDeviceContextCreate()` 10500e6b6b59SJacob Faibussowitsch @*/ 1051d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextViewFromOptions(PetscDeviceContext dctx, PetscObject obj, const char name[]) 1052d71ae5a4SJacob Faibussowitsch { 10530e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 10540e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx)); 10550e6b6b59SJacob Faibussowitsch if (obj) PetscValidHeader(obj, 2); 10560e6b6b59SJacob Faibussowitsch PetscValidCharPointer(name, 3); 10570e6b6b59SJacob Faibussowitsch PetscCall(PetscObjectViewFromOptions(PetscObjectCast(dctx), obj, name)); 10583ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1059030f984aSJacob Faibussowitsch } 106031d47070SJunchao Zhang 106131d47070SJunchao Zhang /*@C 106231d47070SJunchao Zhang PetscDeviceContextGetStreamHandle - Return a handle to the underlying stream of the current device context 106331d47070SJunchao Zhang 106431d47070SJunchao Zhang Input Parameters: 106531d47070SJunchao Zhang + dctx - The `PetscDeviceContext` to get the stream from 106631d47070SJunchao Zhang - handle - A handle to the stream 106731d47070SJunchao Zhang 106831d47070SJunchao Zhang Level: developer 106931d47070SJunchao Zhang 107031d47070SJunchao Zhang Note: 107131d47070SJunchao Zhang This routine is dangerous. It exists only for the most experienced users and 107231d47070SJunchao Zhang internal PETSc developement. 107331d47070SJunchao Zhang 107431d47070SJunchao Zhang There is no way for PETSc's auto-dependency system to track what the caller does with the 107531d47070SJunchao Zhang stream. 107631d47070SJunchao Zhang 107731d47070SJunchao Zhang If the user uses the stream to copy memory that was previously modified by PETSc, or launches 107831d47070SJunchao Zhang kernels that modify memory with the stream, it is the users responsibility to inform PETSc of 107931d47070SJunchao Zhang their actions via `PetscDeviceContextMarkIntentFromID()`. Failure to do so may introduce a 108031d47070SJunchao Zhang race condition. This race condition may manifest in nondeterministic ways. 108131d47070SJunchao Zhang 108231d47070SJunchao Zhang Alternatively, the user may synchronize the stream immediately before and after use. This is 108331d47070SJunchao Zhang the safest option. 108431d47070SJunchao Zhang 108531d47070SJunchao Zhang Example Usage: 108631d47070SJunchao Zhang .vb 108731d47070SJunchao Zhang PetscDeviceContext dctx; 108831d47070SJunchao Zhang PetscDeviceType type; 108931d47070SJunchao Zhang void *handle; 109031d47070SJunchao Zhang 109131d47070SJunchao Zhang PetscDeviceContextGetCurrentContext(&dctx); 109231d47070SJunchao Zhang PetscDeviceContextGetStreamHandle(dctx, &handle); 109331d47070SJunchao Zhang PetscDeviceContextGetDeviceType(dctx, &type); 109431d47070SJunchao Zhang 109531d47070SJunchao Zhang if (type == PETSC_DEVICE_CUDA) { 109631d47070SJunchao Zhang cudsStream_t stream = *(cudaStream_t*)handle; 109731d47070SJunchao Zhang 109831d47070SJunchao Zhang my_cuda_kernel<<<1, 2, 3, stream>>>(); 109931d47070SJunchao Zhang } 110031d47070SJunchao Zhang .ve 110131d47070SJunchao Zhang 110231d47070SJunchao Zhang .N ASYNC_API 110331d47070SJunchao Zhang 110431d47070SJunchao Zhang .seealso: `PetscDeviceContext` 110531d47070SJunchao Zhang @*/ 110631d47070SJunchao Zhang PetscErrorCode PetscDeviceContextGetStreamHandle(PetscDeviceContext dctx, void *handle) 110731d47070SJunchao Zhang { 110831d47070SJunchao Zhang PetscFunctionBegin; 110931d47070SJunchao Zhang PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx)); 111031d47070SJunchao Zhang PetscValidPointer(handle, 2); 111197cd0981SJacob Faibussowitsch PetscCall(PetscDeviceContextGetStreamHandle_Internal(dctx, (void **)handle)); 111231d47070SJunchao Zhang PetscFunctionReturn(PETSC_SUCCESS); 111331d47070SJunchao Zhang } 1114