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 63030f984aSJacob Faibussowitsch /*@C 64811af0c4SBarry Smith PetscDeviceContextCreate - Creates a `PetscDeviceContext` 65030f984aSJacob Faibussowitsch 660e6b6b59SJacob Faibussowitsch Not Collective 67030f984aSJacob Faibussowitsch 68d5b43468SJose E. Roman Output Parameter: 69811af0c4SBarry Smith . dctx - The `PetscDeviceContext` 70030f984aSJacob Faibussowitsch 712fe279fdSBarry Smith Level: beginner 722fe279fdSBarry Smith 73811af0c4SBarry Smith Note: 74030f984aSJacob Faibussowitsch Unlike almost every other PETSc class it is advised that most users use 750e6b6b59SJacob Faibussowitsch `PetscDeviceContextDuplicate()` rather than this routine to create new contexts. Contexts of 760e6b6b59SJacob Faibussowitsch different types are incompatible with one another; using `PetscDeviceContextDuplicate()` 770e6b6b59SJacob Faibussowitsch ensures compatible types. 780e6b6b59SJacob Faibussowitsch 790e6b6b59SJacob Faibussowitsch DAG representation: 800e6b6b59SJacob Faibussowitsch .vb 810e6b6b59SJacob Faibussowitsch time -> 820e6b6b59SJacob Faibussowitsch 830e6b6b59SJacob Faibussowitsch |= CALL =| - dctx -> 840e6b6b59SJacob Faibussowitsch .ve 85030f984aSJacob Faibussowitsch 860e6b6b59SJacob Faibussowitsch .N ASYNC_API 870e6b6b59SJacob Faibussowitsch 88db781477SPatrick Sanan .seealso: `PetscDeviceContextDuplicate()`, `PetscDeviceContextSetDevice()`, 89db781477SPatrick Sanan `PetscDeviceContextSetStreamType()`, `PetscDeviceContextSetUp()`, 900e6b6b59SJacob Faibussowitsch `PetscDeviceContextSetFromOptions()`, `PetscDeviceContextView()`, `PetscDeviceContextDestroy()` 91030f984aSJacob Faibussowitsch @*/ 92d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextCreate(PetscDeviceContext *dctx) 93d71ae5a4SJacob Faibussowitsch { 94030f984aSJacob Faibussowitsch PetscFunctionBegin; 95030f984aSJacob Faibussowitsch PetscValidPointer(dctx, 1); 969566063dSJacob Faibussowitsch PetscCall(PetscDeviceInitializePackage()); 976a4a1270SPierre Jolivet PetscCall(PetscLogEventBegin(DCONTEXT_Create, nullptr, nullptr, nullptr, nullptr)); 980e6b6b59SJacob Faibussowitsch PetscCall(contextPool.allocate(dctx)); 996a4a1270SPierre Jolivet PetscCall(PetscLogEventEnd(DCONTEXT_Create, nullptr, nullptr, nullptr, nullptr)); 1003ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 101030f984aSJacob Faibussowitsch } 102030f984aSJacob Faibussowitsch 103030f984aSJacob Faibussowitsch /*@C 104811af0c4SBarry Smith PetscDeviceContextDestroy - Frees a `PetscDeviceContext` 105030f984aSJacob Faibussowitsch 1060e6b6b59SJacob Faibussowitsch Not Collective 107030f984aSJacob Faibussowitsch 1082fe279fdSBarry Smith Input Parameter: 109811af0c4SBarry Smith . dctx - The `PetscDeviceContext` 110030f984aSJacob Faibussowitsch 1112fe279fdSBarry Smith Level: beginner 1122fe279fdSBarry Smith 1130e6b6b59SJacob Faibussowitsch Notes: 1140e6b6b59SJacob Faibussowitsch No implicit synchronization occurs due to this routine, all resources are released completely 1150e6b6b59SJacob Faibussowitsch asynchronously w.r.t. the host. If one needs to guarantee access to the data produced on 1160e6b6b59SJacob Faibussowitsch `dctx`'s stream the user is responsible for calling `PetscDeviceContextSynchronize()` before 1170e6b6b59SJacob Faibussowitsch calling this routine. 118030f984aSJacob Faibussowitsch 119da81f932SPierre Jolivet DAG representation: 1200e6b6b59SJacob Faibussowitsch .vb 1210e6b6b59SJacob Faibussowitsch time -> 1220e6b6b59SJacob Faibussowitsch 1230e6b6b59SJacob Faibussowitsch -> dctx - |= CALL =| 1240e6b6b59SJacob Faibussowitsch .ve 1250e6b6b59SJacob Faibussowitsch 1260e6b6b59SJacob Faibussowitsch Developer Notes: 1270e6b6b59SJacob Faibussowitsch `dctx` is never actually "destroyed" in the classical sense. It is returned to an ever 1280e6b6b59SJacob Faibussowitsch growing pool of `PetscDeviceContext`s. There are currently no limits on the size of the pool, 1290e6b6b59SJacob Faibussowitsch this should perhaps be implemented. 130030f984aSJacob Faibussowitsch 1310e6b6b59SJacob Faibussowitsch .N ASYNC_API 1320e6b6b59SJacob Faibussowitsch 1330e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextSetDevice()`, 1340e6b6b59SJacob Faibussowitsch `PetscDeviceContextSetUp()`, `PetscDeviceContextSynchronize()` 135030f984aSJacob Faibussowitsch @*/ 136d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextDestroy(PetscDeviceContext *dctx) 137d71ae5a4SJacob Faibussowitsch { 138030f984aSJacob Faibussowitsch PetscFunctionBegin; 1390e6b6b59SJacob Faibussowitsch PetscValidPointer(dctx, 1); 1403ba16761SJacob Faibussowitsch if (!*dctx) PetscFunctionReturn(PETSC_SUCCESS); 1416a4a1270SPierre Jolivet PetscCall(PetscLogEventBegin(DCONTEXT_Destroy, nullptr, nullptr, nullptr, nullptr)); 1420e6b6b59SJacob Faibussowitsch if (--(PetscObjectCast(*dctx)->refct) <= 0) { 1430e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextCheckNotOrphaned_Internal(*dctx)); 144146a86ebSJacob Faibussowitsch PetscCall(contextPool.deallocate(dctx)); 1450e6b6b59SJacob Faibussowitsch } 1466a4a1270SPierre Jolivet PetscCall(PetscLogEventEnd(DCONTEXT_Destroy, nullptr, nullptr, nullptr, nullptr)); 147bf025ffbSJacob Faibussowitsch *dctx = nullptr; 1483ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 149030f984aSJacob Faibussowitsch } 150030f984aSJacob Faibussowitsch 151030f984aSJacob Faibussowitsch /*@C 1520e6b6b59SJacob Faibussowitsch PetscDeviceContextSetStreamType - Set the implementation type of the underlying stream for a 1530e6b6b59SJacob Faibussowitsch `PetscDeviceContext` 154030f984aSJacob Faibussowitsch 1550e6b6b59SJacob Faibussowitsch Not Collective 156030f984aSJacob Faibussowitsch 15701d2d390SJose E. Roman Input Parameters: 158811af0c4SBarry Smith + dctx - The `PetscDeviceContext` 159811af0c4SBarry Smith - type - The `PetscStreamType` 160030f984aSJacob Faibussowitsch 1612fe279fdSBarry Smith Level: beginner 1622fe279fdSBarry Smith 1632fe279fdSBarry Smith Note: 164811af0c4SBarry Smith See `PetscStreamType` in `include/petscdevicetypes.h` for more information on the available 1650e6b6b59SJacob Faibussowitsch types and their interactions. If the `PetscDeviceContext` was previously set up and stream 166811af0c4SBarry Smith type was changed, you must call `PetscDeviceContextSetUp()` again after this routine. 167030f984aSJacob Faibussowitsch 1680e6b6b59SJacob Faibussowitsch .seealso: `PetscStreamType`, `PetscDeviceContextGetStreamType()`, `PetscDeviceContextCreate()`, 1690e6b6b59SJacob Faibussowitsch `PetscDeviceContextSetUp()`, `PetscDeviceContextSetFromOptions()` 170030f984aSJacob Faibussowitsch @*/ 171d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetStreamType(PetscDeviceContext dctx, PetscStreamType type) 172d71ae5a4SJacob Faibussowitsch { 173030f984aSJacob Faibussowitsch PetscFunctionBegin; 1740e6b6b59SJacob Faibussowitsch // do not use getoptionalnullcontext here since we do not want the user to change the stream 1750e6b6b59SJacob Faibussowitsch // type 176030f984aSJacob Faibussowitsch PetscValidDeviceContext(dctx, 1); 177030f984aSJacob Faibussowitsch PetscValidStreamType(type, 2); 1780e6b6b59SJacob Faibussowitsch // only need to do complex swapping if the object has already been setup 179030f984aSJacob Faibussowitsch if (dctx->setup && (dctx->streamType != type)) { 180030f984aSJacob Faibussowitsch dctx->setup = PETSC_FALSE; 1816a4a1270SPierre Jolivet PetscCall(PetscLogEventBegin(DCONTEXT_ChangeStream, dctx, nullptr, nullptr, nullptr)); 1820e6b6b59SJacob Faibussowitsch PetscUseTypeMethod(dctx, changestreamtype, type); 1836a4a1270SPierre Jolivet PetscCall(PetscLogEventEnd(DCONTEXT_ChangeStream, dctx, nullptr, nullptr, nullptr)); 184030f984aSJacob Faibussowitsch } 185030f984aSJacob Faibussowitsch dctx->streamType = type; 1863ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 187030f984aSJacob Faibussowitsch } 188030f984aSJacob Faibussowitsch 189030f984aSJacob Faibussowitsch /*@C 1900e6b6b59SJacob Faibussowitsch PetscDeviceContextGetStreamType - Get the implementation type of the underlying stream for a 1910e6b6b59SJacob Faibussowitsch `PetscDeviceContext` 192030f984aSJacob Faibussowitsch 1930e6b6b59SJacob Faibussowitsch Not Collective 194030f984aSJacob Faibussowitsch 19501d2d390SJose E. Roman Input Parameter: 196811af0c4SBarry Smith . dctx - The `PetscDeviceContext` 197030f984aSJacob Faibussowitsch 198030f984aSJacob Faibussowitsch Output Parameter: 199811af0c4SBarry Smith . type - The `PetscStreamType` 200030f984aSJacob Faibussowitsch 2012fe279fdSBarry Smith Level: beginner 2022fe279fdSBarry Smith 2032fe279fdSBarry Smith Note: 2040e6b6b59SJacob Faibussowitsch See `PetscStreamType` in `include/petscdevicetypes.h` for more information on the available 2050e6b6b59SJacob Faibussowitsch types and their interactions 206030f984aSJacob Faibussowitsch 2070e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextSetStreamType()`, `PetscDeviceContextCreate()`, 2080e6b6b59SJacob Faibussowitsch `PetscDeviceContextSetFromOptions()` 209030f984aSJacob Faibussowitsch @*/ 210d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextGetStreamType(PetscDeviceContext dctx, PetscStreamType *type) 211d71ae5a4SJacob Faibussowitsch { 212030f984aSJacob Faibussowitsch PetscFunctionBegin; 2130e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx)); 214030f984aSJacob Faibussowitsch PetscValidIntPointer(type, 2); 215030f984aSJacob Faibussowitsch *type = dctx->streamType; 2163ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 217030f984aSJacob Faibussowitsch } 218030f984aSJacob Faibussowitsch 2190e6b6b59SJacob Faibussowitsch /* 2200e6b6b59SJacob Faibussowitsch Actual function to set the device. 221030f984aSJacob Faibussowitsch 2220e6b6b59SJacob Faibussowitsch 1. Repeatedly destroying and recreating internal data structures (like streams and events) 2230e6b6b59SJacob Faibussowitsch for recycled PetscDeviceContexts is not free. If done often, it does add up. 2240e6b6b59SJacob Faibussowitsch 2. The vast majority of PetscDeviceContexts are created by PETSc either as children or 22535cb6cd3SPierre Jolivet default contexts. The default contexts *never* change type, and the children are extremely 2260e6b6b59SJacob Faibussowitsch unlikely to (chances are if you fork once, you will fork again very soon). 2270e6b6b59SJacob Faibussowitsch 3. The only time this calculus changes is if the user themselves sets the device type. In 2280e6b6b59SJacob Faibussowitsch this case we do not know what the user has changed, so must always wipe the slate clean. 2290e6b6b59SJacob Faibussowitsch 2300e6b6b59SJacob Faibussowitsch Thus we need to keep track whether the user explicitly sets the device contexts device. 2310e6b6b59SJacob Faibussowitsch */ 232d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDeviceContextSetDevice_Private(PetscDeviceContext dctx, PetscDevice device, PetscBool user_set) 233d71ae5a4SJacob Faibussowitsch { 2340e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 2350e6b6b59SJacob Faibussowitsch // do not use getoptionalnullcontext here since we do not want the user to change its device 2360e6b6b59SJacob Faibussowitsch PetscValidDeviceContext(dctx, 1); 2370e6b6b59SJacob Faibussowitsch PetscValidDevice(device, 2); 2383ba16761SJacob Faibussowitsch if (dctx->device && (dctx->device->id == device->id)) PetscFunctionReturn(PETSC_SUCCESS); 2396a4a1270SPierre Jolivet PetscCall(PetscLogEventBegin(DCONTEXT_SetDevice, dctx, nullptr, nullptr, nullptr)); 2402126a61dSJacob Faibussowitsch PetscTryTypeMethod(dctx, destroy); 2410e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceDestroy(&dctx->device)); 2420e6b6b59SJacob Faibussowitsch PetscCall(PetscMemzero(dctx->ops, sizeof(*dctx->ops))); 2432126a61dSJacob Faibussowitsch PetscCall(PetscDeviceReference_Internal(device)); 2442126a61dSJacob Faibussowitsch // set it before calling the method 2452126a61dSJacob Faibussowitsch dctx->device = device; 2460e6b6b59SJacob Faibussowitsch PetscCall((*device->ops->createcontext)(dctx)); 2476a4a1270SPierre Jolivet PetscCall(PetscLogEventEnd(DCONTEXT_SetDevice, dctx, nullptr, nullptr, nullptr)); 2480e6b6b59SJacob Faibussowitsch dctx->setup = PETSC_FALSE; 2490e6b6b59SJacob Faibussowitsch dctx->usersetdevice = user_set; 2503ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2510e6b6b59SJacob Faibussowitsch } 2520e6b6b59SJacob Faibussowitsch 253d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetDefaultDeviceForType_Internal(PetscDeviceContext dctx, PetscDeviceType type) 254d71ae5a4SJacob Faibussowitsch { 2550e6b6b59SJacob Faibussowitsch PetscDevice device; 2560e6b6b59SJacob Faibussowitsch 2570e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 2580e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceGetDefaultForType_Internal(type, &device)); 2590e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextSetDevice_Private(dctx, device, PETSC_FALSE)); 2603ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2610e6b6b59SJacob Faibussowitsch } 2620e6b6b59SJacob Faibussowitsch 2630e6b6b59SJacob Faibussowitsch /*@C 2640e6b6b59SJacob Faibussowitsch PetscDeviceContextSetDevice - Set the underlying `PetscDevice` for a `PetscDeviceContext` 2650e6b6b59SJacob Faibussowitsch 2660e6b6b59SJacob Faibussowitsch Not Collective 267030f984aSJacob Faibussowitsch 26801d2d390SJose E. Roman Input Parameters: 269811af0c4SBarry Smith + dctx - The `PetscDeviceContext` 270811af0c4SBarry Smith - device - The `PetscDevice` 271030f984aSJacob Faibussowitsch 2722fe279fdSBarry Smith Level: intermediate 2732fe279fdSBarry Smith 274030f984aSJacob Faibussowitsch Notes: 2750e6b6b59SJacob Faibussowitsch This routine is effectively `PetscDeviceContext`'s "set-type" (so every `PetscDeviceContext` must 276da81f932SPierre Jolivet also have an attached `PetscDevice`). Unlike the usual set-type semantics, it is not strictly 2770e6b6b59SJacob Faibussowitsch necessary to set a contexts device to enable usage, any created `PetscDeviceContext`s will 2780e6b6b59SJacob Faibussowitsch always come equipped with the "default" device. 279030f984aSJacob Faibussowitsch 2800e6b6b59SJacob Faibussowitsch This routine is a no-op if `device` is already attached to `dctx`. 281a4af0ceeSJacob Faibussowitsch 2820e6b6b59SJacob Faibussowitsch This routine may (but is very unlikely to) initialize the backend device and may incur 2830e6b6b59SJacob Faibussowitsch synchronization. 2845181c4f9SJacob Faibussowitsch 2850e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceCreate()`, `PetscDeviceConfigure()`, `PetscDeviceContextGetDevice()`, 2860e6b6b59SJacob Faibussowitsch `PetscDeviceContextGetDeviceType()` 287030f984aSJacob Faibussowitsch @*/ 288d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetDevice(PetscDeviceContext dctx, PetscDevice device) 289d71ae5a4SJacob Faibussowitsch { 290030f984aSJacob Faibussowitsch PetscFunctionBegin; 2910e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextSetDevice_Private(dctx, device, PETSC_TRUE)); 2923ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 293030f984aSJacob Faibussowitsch } 294030f984aSJacob Faibussowitsch 295030f984aSJacob Faibussowitsch /*@C 296811af0c4SBarry Smith PetscDeviceContextGetDevice - Get the underlying `PetscDevice` for a `PetscDeviceContext` 297030f984aSJacob Faibussowitsch 2980e6b6b59SJacob Faibussowitsch Not Collective 299030f984aSJacob Faibussowitsch 300030f984aSJacob Faibussowitsch Input Parameter: 301811af0c4SBarry Smith . dctx - the `PetscDeviceContext` 302030f984aSJacob Faibussowitsch 303030f984aSJacob Faibussowitsch Output Parameter: 304811af0c4SBarry Smith . device - The `PetscDevice` 305030f984aSJacob Faibussowitsch 306a375dbeeSPatrick Sanan Level: intermediate 307a375dbeeSPatrick Sanan 3082fe279fdSBarry Smith Note: 3092fe279fdSBarry Smith This is a borrowed reference, the user should not destroy `device`. 3102fe279fdSBarry Smith 3110e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextSetDevice()`, `PetscDevice`, `PetscDeviceContextGetDeviceType()` 312030f984aSJacob Faibussowitsch @*/ 313d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextGetDevice(PetscDeviceContext dctx, PetscDevice *device) 314d71ae5a4SJacob Faibussowitsch { 315030f984aSJacob Faibussowitsch PetscFunctionBegin; 3160e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx)); 317030f984aSJacob Faibussowitsch PetscValidPointer(device, 2); 3180e6b6b59SJacob Faibussowitsch PetscAssert(dctx->device, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "PetscDeviceContext %" PetscInt64_FMT " has no attached PetscDevice to get", PetscObjectCast(dctx)->id); 319030f984aSJacob Faibussowitsch *device = dctx->device; 3203ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 321030f984aSJacob Faibussowitsch } 322030f984aSJacob Faibussowitsch 323030f984aSJacob Faibussowitsch /*@C 3240e6b6b59SJacob Faibussowitsch PetscDeviceContextGetDeviceType - Get the `PetscDeviceType` for a `PetscDeviceContext` 3250e6b6b59SJacob Faibussowitsch 3260e6b6b59SJacob Faibussowitsch Not Collective 3270e6b6b59SJacob Faibussowitsch 3280e6b6b59SJacob Faibussowitsch Input Parameter: 3290e6b6b59SJacob Faibussowitsch . dctx - The `PetscDeviceContext` 3300e6b6b59SJacob Faibussowitsch 3310e6b6b59SJacob Faibussowitsch Output Parameter: 3320e6b6b59SJacob Faibussowitsch . type - The `PetscDeviceType` 3330e6b6b59SJacob Faibussowitsch 3342fe279fdSBarry Smith Level: beginner 3352fe279fdSBarry Smith 3362fe279fdSBarry Smith Note: 3370e6b6b59SJacob Faibussowitsch This routine is a convenience shorthand for `PetscDeviceContextGetDevice()` -> 3380e6b6b59SJacob Faibussowitsch `PetscDeviceGetType()`. 3390e6b6b59SJacob Faibussowitsch 3400e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceType`, `PetscDeviceContextGetDevice()`, `PetscDeviceGetType()`, `PetscDevice` 3410e6b6b59SJacob Faibussowitsch @*/ 342d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextGetDeviceType(PetscDeviceContext dctx, PetscDeviceType *type) 343d71ae5a4SJacob Faibussowitsch { 3440e6b6b59SJacob Faibussowitsch PetscDevice device = nullptr; 3450e6b6b59SJacob Faibussowitsch 3460e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 3470e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx)); 3480e6b6b59SJacob Faibussowitsch PetscValidPointer(type, 2); 3490e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetDevice(dctx, &device)); 3500e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceGetType(device, type)); 3513ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3520e6b6b59SJacob Faibussowitsch } 3530e6b6b59SJacob Faibussowitsch 3540e6b6b59SJacob Faibussowitsch /*@C 355811af0c4SBarry Smith PetscDeviceContextSetUp - Prepares a `PetscDeviceContext` for use 356030f984aSJacob Faibussowitsch 3570e6b6b59SJacob Faibussowitsch Not Collective 358030f984aSJacob Faibussowitsch 35901d2d390SJose E. Roman Input Parameter: 360811af0c4SBarry Smith . dctx - The `PetscDeviceContext` 361030f984aSJacob Faibussowitsch 3622fe279fdSBarry Smith Level: beginner 3632fe279fdSBarry Smith 3642fe279fdSBarry Smith Developer Note: 3650e6b6b59SJacob Faibussowitsch This routine is usually the stage where a `PetscDeviceContext` acquires device-side data 3660e6b6b59SJacob Faibussowitsch structures such as streams, events, and (possibly) handles. 367030f984aSJacob Faibussowitsch 3680e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextSetDevice()`, 3690e6b6b59SJacob Faibussowitsch `PetscDeviceContextDestroy()`, `PetscDeviceContextSetFromOptions()` 370030f984aSJacob Faibussowitsch @*/ 371d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetUp(PetscDeviceContext dctx) 372d71ae5a4SJacob Faibussowitsch { 373030f984aSJacob Faibussowitsch PetscFunctionBegin; 3740e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx)); 3753ba16761SJacob Faibussowitsch if (dctx->setup) PetscFunctionReturn(PETSC_SUCCESS); 3760e6b6b59SJacob Faibussowitsch if (!dctx->device) { 3770e6b6b59SJacob Faibussowitsch const auto default_dtype = PETSC_DEVICE_DEFAULT(); 3780e6b6b59SJacob Faibussowitsch 3790e6b6b59SJacob 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])); 3800e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextSetDefaultDeviceForType_Internal(dctx, default_dtype)); 3810e6b6b59SJacob Faibussowitsch } 3826a4a1270SPierre Jolivet PetscCall(PetscLogEventBegin(DCONTEXT_SetUp, dctx, nullptr, nullptr, nullptr)); 383dbbe0bcdSBarry Smith PetscUseTypeMethod(dctx, setup); 3846a4a1270SPierre Jolivet PetscCall(PetscLogEventEnd(DCONTEXT_SetUp, dctx, nullptr, nullptr, nullptr)); 385030f984aSJacob Faibussowitsch dctx->setup = PETSC_TRUE; 3863ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 387030f984aSJacob Faibussowitsch } 388030f984aSJacob Faibussowitsch 389d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDeviceContextDuplicate_Private(PetscDeviceContext dctx, PetscStreamType stype, PetscDeviceContext *dctxdup) 390d71ae5a4SJacob Faibussowitsch { 3910e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 3926a4a1270SPierre Jolivet PetscCall(PetscLogEventBegin(DCONTEXT_Duplicate, dctx, nullptr, nullptr, nullptr)); 3930e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextCreate(dctxdup)); 3940e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextSetStreamType(*dctxdup, stype)); 3950e6b6b59SJacob Faibussowitsch if (const auto device = dctx->device) PetscCall(PetscDeviceContextSetDevice_Private(*dctxdup, device, dctx->usersetdevice)); 3960e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextSetUp(*dctxdup)); 3976a4a1270SPierre Jolivet PetscCall(PetscLogEventEnd(DCONTEXT_Duplicate, dctx, nullptr, nullptr, nullptr)); 3983ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3990e6b6b59SJacob Faibussowitsch } 4000e6b6b59SJacob Faibussowitsch 401030f984aSJacob Faibussowitsch /*@C 402811af0c4SBarry Smith PetscDeviceContextDuplicate - Duplicates a `PetscDeviceContext` object 403030f984aSJacob Faibussowitsch 4040e6b6b59SJacob Faibussowitsch Not Collective 405030f984aSJacob Faibussowitsch 406030f984aSJacob Faibussowitsch Input Parameter: 407811af0c4SBarry Smith . dctx - The `PetscDeviceContext` to duplicate 408030f984aSJacob Faibussowitsch 4096aad120cSJose E. Roman Output Parameter: 410811af0c4SBarry Smith . dctxdup - The duplicated `PetscDeviceContext` 411030f984aSJacob Faibussowitsch 4122fe279fdSBarry Smith Level: beginner 4132fe279fdSBarry Smith 4140e6b6b59SJacob Faibussowitsch Notes: 4150e6b6b59SJacob Faibussowitsch This is a shorthand method for creating a `PetscDeviceContext` with the exact same settings as 4160e6b6b59SJacob Faibussowitsch another. Note however that `dctxdup` does not share any of the underlying data with `dctx`, 4170e6b6b59SJacob Faibussowitsch (including its current stream-state) they are completely separate objects. 4180e6b6b59SJacob Faibussowitsch 4190e6b6b59SJacob Faibussowitsch There is no implied ordering between `dctx` or `dctxdup`. 4200e6b6b59SJacob Faibussowitsch 4210e6b6b59SJacob Faibussowitsch DAG representation: 4220e6b6b59SJacob Faibussowitsch .vb 4230e6b6b59SJacob Faibussowitsch time -> 4240e6b6b59SJacob Faibussowitsch 4250e6b6b59SJacob Faibussowitsch -> dctx - |= CALL =| - dctx ----> 4260e6b6b59SJacob Faibussowitsch - dctxdup -> 4270e6b6b59SJacob Faibussowitsch .ve 428030f984aSJacob Faibussowitsch 4290e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextSetDevice()`, 4300e6b6b59SJacob Faibussowitsch `PetscDeviceContextSetStreamType()` 431030f984aSJacob Faibussowitsch @*/ 432d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextDuplicate(PetscDeviceContext dctx, PetscDeviceContext *dctxdup) 433d71ae5a4SJacob Faibussowitsch { 4340e6b6b59SJacob Faibussowitsch auto stype = PETSC_STREAM_DEFAULT_BLOCKING; 435030f984aSJacob Faibussowitsch 436030f984aSJacob Faibussowitsch PetscFunctionBegin; 4370e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx)); 438030f984aSJacob Faibussowitsch PetscValidPointer(dctxdup, 2); 4390e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetStreamType(dctx, &stype)); 4400e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextDuplicate_Private(dctx, stype, dctxdup)); 4413ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 442030f984aSJacob Faibussowitsch } 443030f984aSJacob Faibussowitsch 444030f984aSJacob Faibussowitsch /*@C 445811af0c4SBarry Smith PetscDeviceContextQueryIdle - Returns whether or not a `PetscDeviceContext` is idle 446030f984aSJacob Faibussowitsch 4470e6b6b59SJacob Faibussowitsch Not Collective 448030f984aSJacob Faibussowitsch 449030f984aSJacob Faibussowitsch Input Parameter: 4500e6b6b59SJacob Faibussowitsch . dctx - The `PetscDeviceContext` 451030f984aSJacob Faibussowitsch 452030f984aSJacob Faibussowitsch Output Parameter: 4530e6b6b59SJacob Faibussowitsch . idle - `PETSC_TRUE` if `dctx` has NO work, `PETSC_FALSE` if it has work 454030f984aSJacob Faibussowitsch 4552fe279fdSBarry Smith Level: intermediate 4562fe279fdSBarry Smith 457811af0c4SBarry Smith Note: 458ef657721SJacob Faibussowitsch This routine only refers a singular context and does NOT take any of its children into 4590e6b6b59SJacob Faibussowitsch account. That is, if `dctx` is idle but has dependents who do have work this routine still 460811af0c4SBarry Smith returns `PETSC_TRUE`. 461030f984aSJacob Faibussowitsch 462db781477SPatrick Sanan .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextWaitForContext()`, `PetscDeviceContextFork()` 463030f984aSJacob Faibussowitsch @*/ 464d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextQueryIdle(PetscDeviceContext dctx, PetscBool *idle) 465d71ae5a4SJacob Faibussowitsch { 466030f984aSJacob Faibussowitsch PetscFunctionBegin; 4670e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx)); 468030f984aSJacob Faibussowitsch PetscValidBoolPointer(idle, 2); 4696a4a1270SPierre Jolivet PetscCall(PetscLogEventBegin(DCONTEXT_QueryIdle, dctx, nullptr, nullptr, nullptr)); 470dbbe0bcdSBarry Smith PetscUseTypeMethod(dctx, query, idle); 4716a4a1270SPierre Jolivet PetscCall(PetscLogEventEnd(DCONTEXT_QueryIdle, dctx, nullptr, nullptr, nullptr)); 4720e6b6b59SJacob 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")); 4733ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 474030f984aSJacob Faibussowitsch } 475030f984aSJacob Faibussowitsch 476030f984aSJacob Faibussowitsch /*@C 477030f984aSJacob Faibussowitsch PetscDeviceContextWaitForContext - Make one context wait for another context to finish 478030f984aSJacob Faibussowitsch 4790e6b6b59SJacob Faibussowitsch Not Collective 480030f984aSJacob Faibussowitsch 481030f984aSJacob Faibussowitsch Input Parameters: 482811af0c4SBarry Smith + dctxa - The `PetscDeviceContext` object that is waiting 483811af0c4SBarry Smith - dctxb - The `PetscDeviceContext` object that is being waited on 484030f984aSJacob Faibussowitsch 4852fe279fdSBarry Smith Level: beginner 4862fe279fdSBarry Smith 487030f984aSJacob Faibussowitsch Notes: 4880e6b6b59SJacob Faibussowitsch Serializes two `PetscDeviceContext`s. Serialization is performed asynchronously; the host 4890e6b6b59SJacob Faibussowitsch does not wait for the serialization to actually occur. 490811af0c4SBarry Smith 4910e6b6b59SJacob Faibussowitsch This routine uses only the state of `dctxb` at the moment this routine was called, so any 4920e6b6b59SJacob Faibussowitsch future work queued will not affect `dctxa`. It is safe to pass the same context to both 4930e6b6b59SJacob Faibussowitsch arguments (in which case this routine does nothing). 4940e6b6b59SJacob Faibussowitsch 4950e6b6b59SJacob Faibussowitsch DAG representation: 4960e6b6b59SJacob Faibussowitsch .vb 4970e6b6b59SJacob Faibussowitsch time -> 4980e6b6b59SJacob Faibussowitsch 4990e6b6b59SJacob Faibussowitsch -> dctxa ---/- |= CALL =| - dctxa -> 5000e6b6b59SJacob Faibussowitsch / 5010e6b6b59SJacob Faibussowitsch -> dctxb -/------------------------> 5020e6b6b59SJacob Faibussowitsch .ve 503030f984aSJacob Faibussowitsch 5040e6b6b59SJacob Faibussowitsch .N ASYNC_API 5050e6b6b59SJacob Faibussowitsch 506db781477SPatrick Sanan .seealso: `PetscDeviceContextCreate()`, `PetscDeviceContextQueryIdle()`, `PetscDeviceContextJoin()` 507030f984aSJacob Faibussowitsch @*/ 508d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextWaitForContext(PetscDeviceContext dctxa, PetscDeviceContext dctxb) 509d71ae5a4SJacob Faibussowitsch { 5100e6b6b59SJacob Faibussowitsch PetscObject aobj; 5110e6b6b59SJacob Faibussowitsch 512030f984aSJacob Faibussowitsch PetscFunctionBegin; 5130e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctxa)); 5140e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctxb)); 515030f984aSJacob Faibussowitsch PetscCheckCompatibleDeviceContexts(dctxa, 1, dctxb, 2); 5163ba16761SJacob Faibussowitsch if (dctxa == dctxb) PetscFunctionReturn(PETSC_SUCCESS); 5170e6b6b59SJacob Faibussowitsch aobj = PetscObjectCast(dctxa); 5186a4a1270SPierre Jolivet PetscCall(PetscLogEventBegin(DCONTEXT_WaitForCtx, dctxa, dctxb, nullptr, nullptr)); 519dbbe0bcdSBarry Smith PetscUseTypeMethod(dctxa, waitforcontext, dctxb); 5203398534bSJacob Faibussowitsch PetscCallCXX(CxxDataCast(dctxa)->upstream[dctxb] = CxxDataParent(dctxb)); 5216a4a1270SPierre Jolivet PetscCall(PetscLogEventEnd(DCONTEXT_WaitForCtx, dctxa, dctxb, nullptr, nullptr)); 5220e6b6b59SJacob Faibussowitsch PetscCall(PetscInfo(dctxa, "dctx %" PetscInt64_FMT " waiting on dctx %" PetscInt64_FMT "\n", aobj->id, PetscObjectCast(dctxb)->id)); 5230e6b6b59SJacob Faibussowitsch PetscCall(PetscObjectStateIncrease(aobj)); 5243ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 525030f984aSJacob Faibussowitsch } 526030f984aSJacob Faibussowitsch 5270e6b6b59SJacob Faibussowitsch /*@C 5280e6b6b59SJacob Faibussowitsch PetscDeviceContextForkWithStreamType - Create a set of dependent child contexts from a parent 5290e6b6b59SJacob Faibussowitsch context with a prescribed `PetscStreamType` 5300e6b6b59SJacob Faibussowitsch 5310e6b6b59SJacob Faibussowitsch Not Collective, Asynchronous 5320e6b6b59SJacob Faibussowitsch 5330e6b6b59SJacob Faibussowitsch Input Parameters: 5340e6b6b59SJacob Faibussowitsch + dctx - The parent `PetscDeviceContext` 5350e6b6b59SJacob Faibussowitsch . stype - The prescribed `PetscStreamType` 5360e6b6b59SJacob Faibussowitsch - n - The number of children to create 5370e6b6b59SJacob Faibussowitsch 5380e6b6b59SJacob Faibussowitsch Output Parameter: 5390e6b6b59SJacob Faibussowitsch . dsub - The created child context(s) 5400e6b6b59SJacob Faibussowitsch 5412fe279fdSBarry Smith Level: intermediate 5422fe279fdSBarry Smith 5430e6b6b59SJacob Faibussowitsch Notes: 5440e6b6b59SJacob Faibussowitsch This routine creates `n` edges of a DAG from a source node which are causally dependent on the 5450e6b6b59SJacob Faibussowitsch source node. This causal dependency is established as-if by calling 5460e6b6b59SJacob Faibussowitsch `PetscDeviceContextWaitForContext()` on every child. 5470e6b6b59SJacob Faibussowitsch 5480e6b6b59SJacob Faibussowitsch `dsub` is allocated by this routine and has its lifetime bounded by `dctx`. That is, `dctx` 5490e6b6b59SJacob Faibussowitsch expects to free `dsub` (via `PetscDeviceContextJoin()`) before it itself is destroyed. 5500e6b6b59SJacob Faibussowitsch 5510e6b6b59SJacob Faibussowitsch This routine only accounts for work queued on `dctx` up until calling this routine, any 5520e6b6b59SJacob Faibussowitsch subsequent work enqueued on `dctx` has no effect on `dsub`. 5530e6b6b59SJacob Faibussowitsch 5540e6b6b59SJacob Faibussowitsch The `PetscStreamType` of `dctx` does not have to equal `stype`. In fact, it is often the case 5550e6b6b59SJacob Faibussowitsch that they are different. This is useful in cases where a routine can locally exploit stream 5560e6b6b59SJacob Faibussowitsch parallelism without needing to worry about what stream type the incoming `PetscDeviceContext` 5570e6b6b59SJacob Faibussowitsch carries. 5580e6b6b59SJacob Faibussowitsch 5590e6b6b59SJacob Faibussowitsch DAG representation: 5600e6b6b59SJacob Faibussowitsch .vb 5610e6b6b59SJacob Faibussowitsch time -> 5620e6b6b59SJacob Faibussowitsch 5630e6b6b59SJacob Faibussowitsch -> dctx - |= CALL =| -\----> dctx ------> 5640e6b6b59SJacob Faibussowitsch \---> dsub[0] ---> 5650e6b6b59SJacob Faibussowitsch \--> ... -------> 5660e6b6b59SJacob Faibussowitsch \-> dsub[n-1] -> 5670e6b6b59SJacob Faibussowitsch .ve 5680e6b6b59SJacob Faibussowitsch 5690e6b6b59SJacob Faibussowitsch .N ASYNC_API 5700e6b6b59SJacob Faibussowitsch 5710e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextJoin()`, `PetscDeviceContextSynchronize()`, 5720e6b6b59SJacob Faibussowitsch `PetscDeviceContextQueryIdle()`, `PetscDeviceContextWaitForContext()` 5730e6b6b59SJacob Faibussowitsch @*/ 574d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextForkWithStreamType(PetscDeviceContext dctx, PetscStreamType stype, PetscInt n, PetscDeviceContext **dsub) 575d71ae5a4SJacob Faibussowitsch { 5760e6b6b59SJacob Faibussowitsch // debugging only 5770e6b6b59SJacob Faibussowitsch std::string idList; 5780e6b6b59SJacob Faibussowitsch auto ninput = n; 5790e6b6b59SJacob Faibussowitsch 5800e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 5810e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx)); 5820e6b6b59SJacob Faibussowitsch PetscAssert(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of contexts requested %" PetscInt_FMT " < 0", n); 5830e6b6b59SJacob Faibussowitsch PetscValidPointer(dsub, 4); 5840e6b6b59SJacob Faibussowitsch *dsub = nullptr; 5850e6b6b59SJacob Faibussowitsch /* reserve 4 chars per id, 2 for number and 2 for ', ' separator */ 5860e6b6b59SJacob Faibussowitsch if (PetscDefined(USE_DEBUG_AND_INFO)) PetscCallCXX(idList.reserve(4 * n)); 5876a4a1270SPierre Jolivet PetscCall(PetscLogEventBegin(DCONTEXT_Fork, dctx, nullptr, nullptr, nullptr)); 5880e6b6b59SJacob Faibussowitsch /* update child totals */ 5890e6b6b59SJacob Faibussowitsch dctx->numChildren += n; 5900e6b6b59SJacob Faibussowitsch /* now to find out if we have room */ 5910e6b6b59SJacob Faibussowitsch if (dctx->numChildren > dctx->maxNumChildren) { 5920e6b6b59SJacob Faibussowitsch const auto numChildren = dctx->numChildren; 5930e6b6b59SJacob Faibussowitsch auto &maxNumChildren = dctx->maxNumChildren; 5940e6b6b59SJacob Faibussowitsch auto numAllocated = numChildren; 5950e6b6b59SJacob Faibussowitsch 5960e6b6b59SJacob Faibussowitsch /* no room, either from having too many kids or not having any */ 5970e6b6b59SJacob Faibussowitsch if (auto &childIDs = dctx->childIDs) { 5980e6b6b59SJacob Faibussowitsch // the difference is backwards because we have not updated maxNumChildren yet 5990e6b6b59SJacob Faibussowitsch numAllocated -= maxNumChildren; 6000e6b6b59SJacob Faibussowitsch /* have existing children, must reallocate them */ 6010e6b6b59SJacob Faibussowitsch PetscCall(PetscRealloc(numChildren * sizeof(*childIDs), &childIDs)); 6020e6b6b59SJacob Faibussowitsch /* clear the extra memory since realloc doesn't do it for us */ 6030e6b6b59SJacob Faibussowitsch PetscCall(PetscArrayzero(std::next(childIDs, maxNumChildren), numAllocated)); 6040e6b6b59SJacob Faibussowitsch } else { 6050e6b6b59SJacob Faibussowitsch /* have no children */ 6060e6b6b59SJacob Faibussowitsch PetscCall(PetscCalloc1(numChildren, &childIDs)); 6070e6b6b59SJacob Faibussowitsch } 6080e6b6b59SJacob Faibussowitsch /* update total number of children */ 6090e6b6b59SJacob Faibussowitsch maxNumChildren = numChildren; 6100e6b6b59SJacob Faibussowitsch } 6110e6b6b59SJacob Faibussowitsch PetscCall(PetscMalloc1(n, dsub)); 6120e6b6b59SJacob Faibussowitsch for (PetscInt i = 0; ninput && (i < dctx->numChildren); ++i) { 6130e6b6b59SJacob Faibussowitsch auto &childID = dctx->childIDs[i]; 6140e6b6b59SJacob Faibussowitsch /* empty child slot */ 6150e6b6b59SJacob Faibussowitsch if (!childID) { 6160e6b6b59SJacob Faibussowitsch auto &childctx = (*dsub)[i]; 6170e6b6b59SJacob Faibussowitsch 6180e6b6b59SJacob Faibussowitsch /* create the child context in the image of its parent */ 6190e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextDuplicate_Private(dctx, stype, &childctx)); 6200e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextWaitForContext(childctx, dctx)); 6210e6b6b59SJacob Faibussowitsch /* register the child with its parent */ 6220e6b6b59SJacob Faibussowitsch PetscCall(PetscObjectGetId(PetscObjectCast(childctx), &childID)); 6230e6b6b59SJacob Faibussowitsch if (PetscDefined(USE_DEBUG_AND_INFO)) { 6240e6b6b59SJacob Faibussowitsch PetscCallCXX(idList += std::to_string(childID)); 6250e6b6b59SJacob Faibussowitsch if (ninput != 1) PetscCallCXX(idList += ", "); 6260e6b6b59SJacob Faibussowitsch } 6270e6b6b59SJacob Faibussowitsch --ninput; 6280e6b6b59SJacob Faibussowitsch } 6290e6b6b59SJacob Faibussowitsch } 6306a4a1270SPierre Jolivet PetscCall(PetscLogEventEnd(DCONTEXT_Fork, dctx, nullptr, nullptr, nullptr)); 6310e6b6b59SJacob Faibussowitsch PetscCall(PetscDebugInfo(dctx, "Forked %" PetscInt_FMT " children from parent %" PetscInt64_FMT " with IDs: %s\n", n, PetscObjectCast(dctx)->id, idList.c_str())); 6323ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 6330e6b6b59SJacob Faibussowitsch } 6340e6b6b59SJacob Faibussowitsch 635030f984aSJacob Faibussowitsch /*@C 636030f984aSJacob Faibussowitsch PetscDeviceContextFork - Create a set of dependent child contexts from a parent context 637030f984aSJacob Faibussowitsch 638030f984aSJacob Faibussowitsch Not Collective, Asynchronous 639030f984aSJacob Faibussowitsch 640030f984aSJacob Faibussowitsch Input Parameters: 641811af0c4SBarry Smith + dctx - The parent `PetscDeviceContext` 642030f984aSJacob Faibussowitsch - n - The number of children to create 643030f984aSJacob Faibussowitsch 644030f984aSJacob Faibussowitsch Output Parameter: 645030f984aSJacob Faibussowitsch . dsub - The created child context(s) 646030f984aSJacob Faibussowitsch 6472fe279fdSBarry Smith Level: beginner 6482fe279fdSBarry Smith 649030f984aSJacob Faibussowitsch Notes: 6500e6b6b59SJacob Faibussowitsch Behaves identically to `PetscDeviceContextForkWithStreamType()` except that the prescribed 6510e6b6b59SJacob Faibussowitsch `PetscStreamType` is taken from `dctx`. In effect this routine is shorthand for\: 652030f984aSJacob Faibussowitsch 653030f984aSJacob Faibussowitsch .vb 6540e6b6b59SJacob Faibussowitsch PetscStreamType stype; 655030f984aSJacob Faibussowitsch 6560e6b6b59SJacob Faibussowitsch PetscDeviceContextGetStreamType(dctx, &stype); 6570e6b6b59SJacob Faibussowitsch PetscDeviceContextForkWithStreamType(dctx, stype, ...); 658030f984aSJacob Faibussowitsch .ve 659030f984aSJacob Faibussowitsch 6600e6b6b59SJacob Faibussowitsch .N ASYNC_API 6610e6b6b59SJacob Faibussowitsch 6620e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextForkWithStreamType()`, `PetscDeviceContextJoin()`, 6630e6b6b59SJacob Faibussowitsch `PetscDeviceContextSynchronize()`, `PetscDeviceContextQueryIdle()` 664030f984aSJacob Faibussowitsch @*/ 665d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextFork(PetscDeviceContext dctx, PetscInt n, PetscDeviceContext **dsub) 666d71ae5a4SJacob Faibussowitsch { 6670e6b6b59SJacob Faibussowitsch auto stype = PETSC_STREAM_DEFAULT_BLOCKING; 668030f984aSJacob Faibussowitsch 669030f984aSJacob Faibussowitsch PetscFunctionBegin; 6700e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx)); 6710e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetStreamType(dctx, &stype)); 6720e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextForkWithStreamType(dctx, stype, n, dsub)); 6733ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 674030f984aSJacob Faibussowitsch } 675030f984aSJacob Faibussowitsch 676030f984aSJacob Faibussowitsch /*@C 6775181c4f9SJacob Faibussowitsch PetscDeviceContextJoin - Converge a set of child contexts 678030f984aSJacob Faibussowitsch 679030f984aSJacob Faibussowitsch Not Collective, Asynchronous 680030f984aSJacob Faibussowitsch 681030f984aSJacob Faibussowitsch Input Parameters: 682811af0c4SBarry Smith + dctx - A `PetscDeviceContext` to converge on 683030f984aSJacob Faibussowitsch . n - The number of sub contexts to converge 684030f984aSJacob Faibussowitsch . joinMode - The type of join to perform 685030f984aSJacob Faibussowitsch - dsub - The sub contexts to converge 686030f984aSJacob Faibussowitsch 6872fe279fdSBarry Smith Level: beginner 6882fe279fdSBarry Smith 689030f984aSJacob Faibussowitsch Notes: 6900e6b6b59SJacob Faibussowitsch If `PetscDeviceContextFork()` creates `n` edges from a source node which all depend on the source 6910e6b6b59SJacob Faibussowitsch node, then this routine is the exact mirror. That is, it creates a node (represented in `dctx`) 69235cb6cd3SPierre Jolivet which receives `n` edges (and optionally destroys them) which is dependent on the completion 6930e6b6b59SJacob Faibussowitsch of all incoming edges. 694030f984aSJacob Faibussowitsch 6950e6b6b59SJacob Faibussowitsch If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_DESTROY`. All contexts in `dsub` will be 6960e6b6b59SJacob Faibussowitsch destroyed by this routine. Thus all sub contexts must have been created with the `dctx` 6970e6b6b59SJacob Faibussowitsch passed to this routine. 698030f984aSJacob Faibussowitsch 6990e6b6b59SJacob Faibussowitsch If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_SYNC`. All sub contexts will additionally wait on 7000e6b6b59SJacob Faibussowitsch `dctx` after converging. This has the effect of "synchronizing" the outgoing edges. Note the 7010e6b6b59SJacob Faibussowitsch sync suffix does NOT refer to the host, i.e. this routine does NOT call 7020e6b6b59SJacob Faibussowitsch `PetscDeviceSynchronize()`. 703030f984aSJacob Faibussowitsch 7040e6b6b59SJacob Faibussowitsch If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC`. `dctx` waits for all sub contexts but 7050e6b6b59SJacob Faibussowitsch the sub contexts do not wait for one another or `dctx` afterwards. 706030f984aSJacob Faibussowitsch 707030f984aSJacob Faibussowitsch DAG representations: 708811af0c4SBarry Smith If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_DESTROY` 709030f984aSJacob Faibussowitsch .vb 710030f984aSJacob Faibussowitsch time -> 711030f984aSJacob Faibussowitsch 7120e6b6b59SJacob Faibussowitsch -> dctx ---------/- |= CALL =| - dctx -> 713030f984aSJacob Faibussowitsch -> dsub[0] -----/ 714030f984aSJacob Faibussowitsch -> ... -------/ 715030f984aSJacob Faibussowitsch -> dsub[n-1] -/ 716030f984aSJacob Faibussowitsch .ve 717811af0c4SBarry Smith If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_SYNC` 718030f984aSJacob Faibussowitsch .vb 719030f984aSJacob Faibussowitsch time -> 720030f984aSJacob Faibussowitsch 7210e6b6b59SJacob Faibussowitsch -> dctx ---------/- |= CALL =| -\----> dctx ------> 722030f984aSJacob Faibussowitsch -> dsub[0] -----/ \---> dsub[0] ---> 723030f984aSJacob Faibussowitsch -> ... -------/ \--> ... -------> 724030f984aSJacob Faibussowitsch -> dsub[n-1] -/ \-> dsub[n-1] -> 725030f984aSJacob Faibussowitsch .ve 7260e6b6b59SJacob Faibussowitsch If `joinMode` is `PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC` 7270e6b6b59SJacob Faibussowitsch .vb 7280e6b6b59SJacob Faibussowitsch time -> 729030f984aSJacob Faibussowitsch 7300e6b6b59SJacob Faibussowitsch -> dctx ----------/- |= CALL =| - dctx -> 7310e6b6b59SJacob Faibussowitsch -> dsub[0] ------/-----------------------> 7320e6b6b59SJacob Faibussowitsch -> ... --------/------------------------> 7330e6b6b59SJacob Faibussowitsch -> dsub[n-1] --/-------------------------> 7340e6b6b59SJacob Faibussowitsch .ve 735030f984aSJacob Faibussowitsch 7360e6b6b59SJacob Faibussowitsch .N ASYNC_API 7370e6b6b59SJacob Faibussowitsch 7380e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextFork()`, `PetscDeviceContextForkWithStreamType()`, 7390e6b6b59SJacob Faibussowitsch `PetscDeviceContextSynchronize()`, `PetscDeviceContextJoinMode` 740030f984aSJacob Faibussowitsch @*/ 741d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextJoin(PetscDeviceContext dctx, PetscInt n, PetscDeviceContextJoinMode joinMode, PetscDeviceContext **dsub) 742d71ae5a4SJacob Faibussowitsch { 7430e6b6b59SJacob Faibussowitsch // debugging only 7440e6b6b59SJacob Faibussowitsch std::string idList; 745030f984aSJacob Faibussowitsch 746030f984aSJacob Faibussowitsch PetscFunctionBegin; 7470e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx)); 748030f984aSJacob Faibussowitsch /* validity of dctx is checked in the wait-for loop */ 749030f984aSJacob Faibussowitsch PetscValidPointer(dsub, 4); 750bf025ffbSJacob Faibussowitsch PetscAssert(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of contexts merged %" PetscInt_FMT " < 0", n); 751030f984aSJacob Faibussowitsch /* reserve 4 chars per id, 2 for number and 2 for ', ' separator */ 7520e6b6b59SJacob Faibussowitsch if (PetscDefined(USE_DEBUG_AND_INFO)) PetscCallCXX(idList.reserve(4 * n)); 753030f984aSJacob Faibussowitsch /* first dctx waits on all the incoming edges */ 7546a4a1270SPierre Jolivet PetscCall(PetscLogEventBegin(DCONTEXT_Join, dctx, nullptr, nullptr, nullptr)); 755030f984aSJacob Faibussowitsch for (PetscInt i = 0; i < n; ++i) { 756030f984aSJacob Faibussowitsch PetscCheckCompatibleDeviceContexts(dctx, 1, (*dsub)[i], 4); 7579566063dSJacob Faibussowitsch PetscCall(PetscDeviceContextWaitForContext(dctx, (*dsub)[i])); 7580e6b6b59SJacob Faibussowitsch if (PetscDefined(USE_DEBUG_AND_INFO)) { 7590e6b6b59SJacob Faibussowitsch PetscCallCXX(idList += std::to_string(PetscObjectCast((*dsub)[i])->id)); 7600e6b6b59SJacob Faibussowitsch if (i + 1 < n) PetscCallCXX(idList += ", "); 7610e6b6b59SJacob Faibussowitsch } 762030f984aSJacob Faibussowitsch } 763030f984aSJacob Faibussowitsch 764030f984aSJacob Faibussowitsch /* now we handle the aftermath */ 765030f984aSJacob Faibussowitsch switch (joinMode) { 7669371c9d4SSatish Balay case PETSC_DEVICE_CONTEXT_JOIN_DESTROY: { 7670e6b6b59SJacob Faibussowitsch const auto children = dctx->childIDs; 7680e6b6b59SJacob Faibussowitsch const auto maxchild = dctx->maxNumChildren; 7690e6b6b59SJacob Faibussowitsch auto &nchild = dctx->numChildren; 770030f984aSJacob Faibussowitsch PetscInt j = 0; 771030f984aSJacob Faibussowitsch 7720e6b6b59SJacob 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); 773030f984aSJacob Faibussowitsch /* update child count while it's still fresh in memory */ 7740e6b6b59SJacob Faibussowitsch nchild -= n; 7750e6b6b59SJacob Faibussowitsch for (PetscInt i = 0; i < maxchild; ++i) { 7760e6b6b59SJacob Faibussowitsch if (children[i] && (children[i] == PetscObjectCast((*dsub)[j])->id)) { 777030f984aSJacob Faibussowitsch /* child is one of ours, can destroy it */ 7789566063dSJacob Faibussowitsch PetscCall(PetscDeviceContextDestroy((*dsub) + j)); 779030f984aSJacob Faibussowitsch /* reset the child slot */ 7800e6b6b59SJacob Faibussowitsch children[i] = 0; 781030f984aSJacob Faibussowitsch if (++j == n) break; 782030f984aSJacob Faibussowitsch } 783030f984aSJacob Faibussowitsch } 7840e6b6b59SJacob Faibussowitsch /* gone through the loop but did not find every child */ 7850e6b6b59SJacob 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); 7869566063dSJacob Faibussowitsch PetscCall(PetscFree(*dsub)); 7879371c9d4SSatish Balay } break; 788030f984aSJacob Faibussowitsch case PETSC_DEVICE_CONTEXT_JOIN_SYNC: 7899566063dSJacob Faibussowitsch for (PetscInt i = 0; i < n; ++i) PetscCall(PetscDeviceContextWaitForContext((*dsub)[i], dctx)); 790d71ae5a4SJacob Faibussowitsch case PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC: 791d71ae5a4SJacob Faibussowitsch break; 792d71ae5a4SJacob Faibussowitsch default: 793d71ae5a4SJacob Faibussowitsch SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown PetscDeviceContextJoinMode given"); 794030f984aSJacob Faibussowitsch } 7956a4a1270SPierre Jolivet PetscCall(PetscLogEventEnd(DCONTEXT_Join, dctx, nullptr, nullptr, nullptr)); 796030f984aSJacob Faibussowitsch 7970e6b6b59SJacob 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())); 7983ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 799030f984aSJacob Faibussowitsch } 800030f984aSJacob Faibussowitsch 801030f984aSJacob Faibussowitsch /*@C 8020e6b6b59SJacob Faibussowitsch PetscDeviceContextSynchronize - Block the host until all work queued on a 8030e6b6b59SJacob Faibussowitsch `PetscDeviceContext` has finished 804030f984aSJacob Faibussowitsch 8050e6b6b59SJacob Faibussowitsch Not Collective 806030f984aSJacob Faibussowitsch 8072fe279fdSBarry Smith Input Parameter: 808811af0c4SBarry Smith . dctx - The `PetscDeviceContext` to synchronize 809030f984aSJacob Faibussowitsch 8102fe279fdSBarry Smith Level: beginner 8112fe279fdSBarry Smith 8120e6b6b59SJacob Faibussowitsch Notes: 8130e6b6b59SJacob Faibussowitsch The host will not return from this routine until `dctx` is idle. Any and all memory 8140e6b6b59SJacob Faibussowitsch operations queued on or otherwise associated with (either explicitly or implicitly via 8150e6b6b59SJacob Faibussowitsch dependencies) are guaranteed to have finished and be globally visible on return. 8160e6b6b59SJacob Faibussowitsch 8170e6b6b59SJacob Faibussowitsch In effect, this routine serves as memory and execution barrier. 8180e6b6b59SJacob Faibussowitsch 8190e6b6b59SJacob Faibussowitsch DAG representation: 8200e6b6b59SJacob Faibussowitsch .vb 8210e6b6b59SJacob Faibussowitsch time -> 8220e6b6b59SJacob Faibussowitsch 8230e6b6b59SJacob Faibussowitsch -> dctx - |= CALL =| - dctx -> 8240e6b6b59SJacob Faibussowitsch .ve 8250e6b6b59SJacob Faibussowitsch 826db781477SPatrick Sanan .seealso: `PetscDeviceContextFork()`, `PetscDeviceContextJoin()`, `PetscDeviceContextQueryIdle()` 827030f984aSJacob Faibussowitsch @*/ 828d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextSynchronize(PetscDeviceContext dctx) 829d71ae5a4SJacob Faibussowitsch { 830030f984aSJacob Faibussowitsch PetscFunctionBegin; 8310e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx)); 8326a4a1270SPierre Jolivet PetscCall(PetscLogEventBegin(DCONTEXT_Sync, dctx, nullptr, nullptr, nullptr)); 833030f984aSJacob Faibussowitsch /* if it isn't setup there is nothing to sync on */ 8340e6b6b59SJacob Faibussowitsch if (dctx->setup) { 8352f85e401SJacob Faibussowitsch PetscUseTypeMethod(dctx, synchronize); 8360e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextSyncClearMap_Internal(dctx)); 8370e6b6b59SJacob Faibussowitsch } 8386a4a1270SPierre Jolivet PetscCall(PetscLogEventEnd(DCONTEXT_Sync, dctx, nullptr, nullptr, nullptr)); 8393ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 840030f984aSJacob Faibussowitsch } 841030f984aSJacob Faibussowitsch 8420e6b6b59SJacob Faibussowitsch /* every device type has a vector of null PetscDeviceContexts -- one for each device */ 8430e6b6b59SJacob Faibussowitsch static auto nullContexts = std::array<std::vector<PetscDeviceContext>, PETSC_DEVICE_MAX>{}; 8440e6b6b59SJacob Faibussowitsch static auto nullContextsFinalizer = false; 845030f984aSJacob Faibussowitsch 846d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDeviceContextGetNullContextForDevice_Private(PetscBool user_set_device, PetscDevice device, PetscDeviceContext *dctx) 847d71ae5a4SJacob Faibussowitsch { 8480e6b6b59SJacob Faibussowitsch PetscInt devid; 8490e6b6b59SJacob Faibussowitsch PetscDeviceType dtype; 850a4af0ceeSJacob Faibussowitsch 851030f984aSJacob Faibussowitsch PetscFunctionBegin; 8520e6b6b59SJacob Faibussowitsch PetscValidDevice(device, 2); 8530e6b6b59SJacob Faibussowitsch PetscValidPointer(dctx, 3); 8540e6b6b59SJacob Faibussowitsch if (PetscUnlikely(!nullContextsFinalizer)) { 8550e6b6b59SJacob Faibussowitsch const auto finalizer = [] { 8560e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 8570e6b6b59SJacob Faibussowitsch for (auto &&dvec : nullContexts) { 8580e6b6b59SJacob Faibussowitsch for (auto &&dctx : dvec) PetscCall(PetscDeviceContextDestroy(&dctx)); 8590e6b6b59SJacob Faibussowitsch PetscCallCXX(dvec.clear()); 860030f984aSJacob Faibussowitsch } 8610e6b6b59SJacob Faibussowitsch nullContextsFinalizer = false; 8623ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 863a4af0ceeSJacob Faibussowitsch }; 864a4af0ceeSJacob Faibussowitsch 8650e6b6b59SJacob Faibussowitsch nullContextsFinalizer = true; 8660e6b6b59SJacob Faibussowitsch PetscCall(PetscRegisterFinalize(std::move(finalizer))); 8670e6b6b59SJacob Faibussowitsch } 8680e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceGetDeviceId(device, &devid)); 8690e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceGetType(device, &dtype)); 8700e6b6b59SJacob Faibussowitsch { 8710e6b6b59SJacob Faibussowitsch auto &ctxlist = nullContexts[dtype]; 8720e6b6b59SJacob Faibussowitsch 8730e6b6b59SJacob Faibussowitsch PetscCheck(devid >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Device ID (%" PetscInt_FMT ") must be positive", devid); 8740e6b6b59SJacob Faibussowitsch // need to resize the container if not big enough because incrementing the iterator in 8750e6b6b59SJacob Faibussowitsch // std::next() (if we haven't initialized that ctx yet) may cause it to fall outside the 8760e6b6b59SJacob Faibussowitsch // current size of the container. 8770e6b6b59SJacob Faibussowitsch if (static_cast<std::size_t>(devid) >= ctxlist.size()) PetscCallCXX(ctxlist.resize(devid + 1)); 8780e6b6b59SJacob Faibussowitsch if (PetscUnlikely(!ctxlist[devid])) { 8790e6b6b59SJacob Faibussowitsch // we have not seen this device before 8800e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextCreate(dctx)); 881403f9ca4SJacob Faibussowitsch PetscCall(PetscInfo(*dctx, "Initializing null PetscDeviceContext (of type %s) for device %" PetscInt_FMT "\n", PetscDeviceTypes[dtype], devid)); 8820e6b6b59SJacob Faibussowitsch { 8830e6b6b59SJacob Faibussowitsch const auto pobj = PetscObjectCast(*dctx); 8840e6b6b59SJacob Faibussowitsch const auto name = "null context " + std::to_string(devid); 8850e6b6b59SJacob Faibussowitsch const auto prefix = "null_context_" + std::to_string(devid) + '_'; 8860e6b6b59SJacob Faibussowitsch 8870e6b6b59SJacob Faibussowitsch PetscCall(PetscObjectSetName(pobj, name.c_str())); 8880e6b6b59SJacob Faibussowitsch PetscCall(PetscObjectSetOptionsPrefix(pobj, prefix.c_str())); 8890e6b6b59SJacob Faibussowitsch } 8900e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextSetStreamType(*dctx, PETSC_STREAM_GLOBAL_BLOCKING)); 8910e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextSetDevice_Private(*dctx, device, user_set_device)); 8920e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextSetUp(*dctx)); 8930e6b6b59SJacob Faibussowitsch // would use ctxlist.cbegin() but GCC 4.8 can't handle const iterator insert! 8940e6b6b59SJacob Faibussowitsch PetscCallCXX(ctxlist.insert(std::next(ctxlist.begin(), devid), *dctx)); 8950e6b6b59SJacob Faibussowitsch } else *dctx = ctxlist[devid]; 8960e6b6b59SJacob Faibussowitsch } 8973ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 898030f984aSJacob Faibussowitsch } 899030f984aSJacob Faibussowitsch 9000e6b6b59SJacob Faibussowitsch /* 9010e6b6b59SJacob Faibussowitsch Gets the "NULL" context for the current PetscDeviceType and PetscDevice. NULL contexts are 9020e6b6b59SJacob Faibussowitsch guaranteed to always be globally blocking. 9030e6b6b59SJacob Faibussowitsch */ 904d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextGetNullContext_Internal(PetscDeviceContext *dctx) 905d71ae5a4SJacob Faibussowitsch { 9060e6b6b59SJacob Faibussowitsch PetscDeviceContext gctx; 9070e6b6b59SJacob Faibussowitsch PetscDevice gdev = nullptr; 908030f984aSJacob Faibussowitsch 909a4af0ceeSJacob Faibussowitsch PetscFunctionBegin; 910a4af0ceeSJacob Faibussowitsch PetscValidPointer(dctx, 1); 9110e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetCurrentContext(&gctx)); 9120e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetDevice(gctx, &gdev)); 9130e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetNullContextForDevice_Private(gctx->usersetdevice, gdev, dctx)); 9143ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 915030f984aSJacob Faibussowitsch } 916030f984aSJacob Faibussowitsch 917030f984aSJacob Faibussowitsch /*@C 918811af0c4SBarry Smith PetscDeviceContextSetFromOptions - Configure a `PetscDeviceContext` from the options database 919030f984aSJacob Faibussowitsch 9200e6b6b59SJacob Faibussowitsch Collective on `comm` or `dctx` 921030f984aSJacob Faibussowitsch 922030f984aSJacob Faibussowitsch Input Parameters: 9230e6b6b59SJacob Faibussowitsch + comm - MPI communicator on which to query the options database (optional) 924811af0c4SBarry Smith - dctx - The `PetscDeviceContext` to configure 925030f984aSJacob Faibussowitsch 926030f984aSJacob Faibussowitsch Output Parameter: 927811af0c4SBarry Smith . dctx - The `PetscDeviceContext` 928030f984aSJacob Faibussowitsch 9293c7db156SBarry Smith Options Database Keys: 9300e6b6b59SJacob Faibussowitsch + -device_context_stream_type - type of stream to create inside the `PetscDeviceContext` - 9310e6b6b59SJacob Faibussowitsch `PetscDeviceContextSetStreamType()` 932811af0c4SBarry Smith - -device_context_device_type - the type of `PetscDevice` to attach by default - `PetscDeviceType` 933030f984aSJacob Faibussowitsch 9342fe279fdSBarry Smith Level: beginner 9352fe279fdSBarry Smith 9362fe279fdSBarry Smith Note: 9370e6b6b59SJacob Faibussowitsch The user may pass `MPI_COMM_NULL` for `comm` in which case the communicator of `dctx` is 9380e6b6b59SJacob Faibussowitsch used (which is always `PETSC_COMM_SELF`). 9390e6b6b59SJacob Faibussowitsch 9400e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextSetStreamType()`, `PetscDeviceContextSetDevice()`, 9410e6b6b59SJacob Faibussowitsch `PetscDeviceContextView()` 942030f984aSJacob Faibussowitsch @*/ 943d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextSetFromOptions(MPI_Comm comm, PetscDeviceContext dctx) 944d71ae5a4SJacob Faibussowitsch { 9450e6b6b59SJacob Faibussowitsch const auto pobj = PetscObjectCast(dctx); 9460e6b6b59SJacob Faibussowitsch auto dtype = std::make_pair(PETSC_DEVICE_DEFAULT(), PETSC_FALSE); 9470e6b6b59SJacob Faibussowitsch auto stype = std::make_pair(PETSC_DEVICE_CONTEXT_DEFAULT_STREAM_TYPE, PETSC_FALSE); 948e6b8bd2aSJacob Faibussowitsch MPI_Comm old_comm = PETSC_COMM_SELF; 949030f984aSJacob Faibussowitsch 950030f984aSJacob Faibussowitsch PetscFunctionBegin; 9510e6b6b59SJacob Faibussowitsch // do not user getoptionalnullcontext here, the user is not allowed to set it from options! 9520e6b6b59SJacob Faibussowitsch PetscValidDeviceContext(dctx, 2); 9530e6b6b59SJacob Faibussowitsch /* set the device type first */ 9540e6b6b59SJacob Faibussowitsch if (const auto device = dctx->device) PetscCall(PetscDeviceGetType(device, &dtype.first)); 9550e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetStreamType(dctx, &stype.first)); 9560e6b6b59SJacob Faibussowitsch 9570e6b6b59SJacob Faibussowitsch if (comm == MPI_COMM_NULL) { 9580e6b6b59SJacob Faibussowitsch PetscCall(PetscObjectGetComm(pobj, &comm)); 9590e6b6b59SJacob Faibussowitsch } else { 9600e6b6b59SJacob Faibussowitsch // briefly set the communicator for dctx (it is always PETSC_COMM_SELF) so 9610e6b6b59SJacob Faibussowitsch // PetscObjectOptionsBegin() behaves as if dctx had comm 9620e6b6b59SJacob Faibussowitsch old_comm = Petsc::util::exchange(pobj->comm, comm); 9630e6b6b59SJacob Faibussowitsch } 9640e6b6b59SJacob Faibussowitsch 9650e6b6b59SJacob Faibussowitsch PetscObjectOptionsBegin(pobj); 9660e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextQueryOptions_Internal(PetscOptionsObject, dtype, stype)); 967d0609cedSBarry Smith PetscOptionsEnd(); 9680e6b6b59SJacob Faibussowitsch // reset the comm (should be PETSC_COMM_SELF) 9690e6b6b59SJacob Faibussowitsch if (comm != MPI_COMM_NULL) pobj->comm = old_comm; 9700e6b6b59SJacob Faibussowitsch if (dtype.second) PetscCall(PetscDeviceContextSetDefaultDeviceForType_Internal(dctx, dtype.first)); 9710e6b6b59SJacob Faibussowitsch if (stype.second) PetscCall(PetscDeviceContextSetStreamType(dctx, stype.first)); 9720e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextSetUp(dctx)); 9733ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 9740e6b6b59SJacob Faibussowitsch } 9750e6b6b59SJacob Faibussowitsch 9760e6b6b59SJacob Faibussowitsch /*@C 9770e6b6b59SJacob Faibussowitsch PetscDeviceContextView - View a `PetscDeviceContext` 9780e6b6b59SJacob Faibussowitsch 9790e6b6b59SJacob Faibussowitsch Collective on `viewer` 9800e6b6b59SJacob Faibussowitsch 9810e6b6b59SJacob Faibussowitsch Input Parameters: 9820e6b6b59SJacob Faibussowitsch + dctx - The `PetscDeviceContext` 9830e6b6b59SJacob Faibussowitsch - viewer - The `PetscViewer` to view `dctx` with (may be `NULL`) 9840e6b6b59SJacob Faibussowitsch 9852fe279fdSBarry Smith Level: beginner 9862fe279fdSBarry Smith 9872fe279fdSBarry Smith Note: 9880e6b6b59SJacob Faibussowitsch If `viewer` is `NULL`, `PETSC_VIEWER_STDOUT_WORLD` is used instead, in which case this 9890e6b6b59SJacob Faibussowitsch routine is collective on `PETSC_COMM_WORLD`. 9900e6b6b59SJacob Faibussowitsch 9910e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextViewFromOptions()`, `PetscDeviceView()`, `PETSC_VIEWER_STDOUT_WORLD`, `PetscDeviceContextCreate()` 9920e6b6b59SJacob Faibussowitsch @*/ 993d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextView(PetscDeviceContext dctx, PetscViewer viewer) 994d71ae5a4SJacob Faibussowitsch { 9950e6b6b59SJacob Faibussowitsch PetscBool iascii; 9960e6b6b59SJacob Faibussowitsch 9970e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 9980e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx)); 9990e6b6b59SJacob Faibussowitsch if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PETSC_COMM_WORLD, &viewer)); 10000e6b6b59SJacob Faibussowitsch PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 10010e6b6b59SJacob Faibussowitsch PetscCall(PetscObjectTypeCompare(PetscObjectCast(viewer), PETSCVIEWERASCII, &iascii)); 10020e6b6b59SJacob Faibussowitsch if (iascii) { 10030e6b6b59SJacob Faibussowitsch auto stype = PETSC_STREAM_DEFAULT_BLOCKING; 10040e6b6b59SJacob Faibussowitsch PetscViewer sub; 10050e6b6b59SJacob Faibussowitsch 10060e6b6b59SJacob Faibussowitsch PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sub)); 10070e6b6b59SJacob Faibussowitsch PetscCall(PetscObjectPrintClassNamePrefixType(PetscObjectCast(dctx), sub)); 10080e6b6b59SJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(sub)); 10090e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetStreamType(dctx, &stype)); 10100e6b6b59SJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(sub, "stream type: %s\n", PetscStreamTypes[stype])); 10110e6b6b59SJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(sub, "children: %" PetscInt_FMT "\n", dctx->numChildren)); 10120e6b6b59SJacob Faibussowitsch if (const auto nchild = dctx->numChildren) { 10130e6b6b59SJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(sub)); 10140e6b6b59SJacob Faibussowitsch for (PetscInt i = 0; i < nchild; ++i) { 10150e6b6b59SJacob Faibussowitsch if (i == nchild - 1) { 10160e6b6b59SJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(sub, "%" PetscInt64_FMT, dctx->childIDs[i])); 10170e6b6b59SJacob Faibussowitsch } else { 10180e6b6b59SJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(sub, "%" PetscInt64_FMT ", ", dctx->childIDs[i])); 10190e6b6b59SJacob Faibussowitsch } 10200e6b6b59SJacob Faibussowitsch } 10210e6b6b59SJacob Faibussowitsch } 10220e6b6b59SJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(sub)); 10230e6b6b59SJacob Faibussowitsch PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sub)); 10240e6b6b59SJacob Faibussowitsch PetscCall(PetscViewerFlush(viewer)); 10250e6b6b59SJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer)); 10260e6b6b59SJacob Faibussowitsch } 10270e6b6b59SJacob Faibussowitsch if (const auto device = dctx->device) PetscCall(PetscDeviceView(device, viewer)); 10280e6b6b59SJacob Faibussowitsch if (iascii) PetscCall(PetscViewerASCIIPopTab(viewer)); 10293ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 10300e6b6b59SJacob Faibussowitsch } 10310e6b6b59SJacob Faibussowitsch 10320e6b6b59SJacob Faibussowitsch /*@C 10330e6b6b59SJacob Faibussowitsch PetscDeviceContextViewFromOptions - View a `PetscDeviceContext` from options 10340e6b6b59SJacob Faibussowitsch 10350e6b6b59SJacob Faibussowitsch Input Parameters: 10360e6b6b59SJacob Faibussowitsch + dctx - The `PetscDeviceContext` to view 10370e6b6b59SJacob Faibussowitsch . obj - Optional `PetscObject` to associate (may be `NULL`) 10380e6b6b59SJacob Faibussowitsch - name - The command line option 10390e6b6b59SJacob Faibussowitsch 10400e6b6b59SJacob Faibussowitsch Level: beginner 10410e6b6b59SJacob Faibussowitsch 10420e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextView()`, `PetscObjectViewFromOptions()`, `PetscDeviceContextCreate()` 10430e6b6b59SJacob Faibussowitsch @*/ 1044d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextViewFromOptions(PetscDeviceContext dctx, PetscObject obj, const char name[]) 1045d71ae5a4SJacob Faibussowitsch { 10460e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 10470e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx)); 10480e6b6b59SJacob Faibussowitsch if (obj) PetscValidHeader(obj, 2); 10490e6b6b59SJacob Faibussowitsch PetscValidCharPointer(name, 3); 10500e6b6b59SJacob Faibussowitsch PetscCall(PetscObjectViewFromOptions(PetscObjectCast(dctx), obj, name)); 10513ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1052030f984aSJacob Faibussowitsch } 1053*31d47070SJunchao Zhang 1054*31d47070SJunchao Zhang /*@C 1055*31d47070SJunchao Zhang PetscDeviceContextGetStreamHandle - Return a handle to the underlying stream of the current device context 1056*31d47070SJunchao Zhang 1057*31d47070SJunchao Zhang Input Parameters: 1058*31d47070SJunchao Zhang + dctx - The `PetscDeviceContext` to get the stream from 1059*31d47070SJunchao Zhang - handle - A handle to the stream 1060*31d47070SJunchao Zhang 1061*31d47070SJunchao Zhang Level: developer 1062*31d47070SJunchao Zhang 1063*31d47070SJunchao Zhang Note: 1064*31d47070SJunchao Zhang This routine is dangerous. It exists only for the most experienced users and 1065*31d47070SJunchao Zhang internal PETSc developement. 1066*31d47070SJunchao Zhang 1067*31d47070SJunchao Zhang There is no way for PETSc's auto-dependency system to track what the caller does with the 1068*31d47070SJunchao Zhang stream. 1069*31d47070SJunchao Zhang 1070*31d47070SJunchao Zhang If the user uses the stream to copy memory that was previously modified by PETSc, or launches 1071*31d47070SJunchao Zhang kernels that modify memory with the stream, it is the users responsibility to inform PETSc of 1072*31d47070SJunchao Zhang their actions via `PetscDeviceContextMarkIntentFromID()`. Failure to do so may introduce a 1073*31d47070SJunchao Zhang race condition. This race condition may manifest in nondeterministic ways. 1074*31d47070SJunchao Zhang 1075*31d47070SJunchao Zhang Alternatively, the user may synchronize the stream immediately before and after use. This is 1076*31d47070SJunchao Zhang the safest option. 1077*31d47070SJunchao Zhang 1078*31d47070SJunchao Zhang Example Usage: 1079*31d47070SJunchao Zhang .vb 1080*31d47070SJunchao Zhang PetscDeviceContext dctx; 1081*31d47070SJunchao Zhang PetscDeviceType type; 1082*31d47070SJunchao Zhang void *handle; 1083*31d47070SJunchao Zhang 1084*31d47070SJunchao Zhang PetscDeviceContextGetCurrentContext(&dctx); 1085*31d47070SJunchao Zhang PetscDeviceContextGetStreamHandle(dctx, &handle); 1086*31d47070SJunchao Zhang PetscDeviceContextGetDeviceType(dctx, &type); 1087*31d47070SJunchao Zhang 1088*31d47070SJunchao Zhang if (type == PETSC_DEVICE_CUDA) { 1089*31d47070SJunchao Zhang cudsStream_t stream = *(cudaStream_t*)handle; 1090*31d47070SJunchao Zhang 1091*31d47070SJunchao Zhang my_cuda_kernel<<<1, 2, 3, stream>>>(); 1092*31d47070SJunchao Zhang } 1093*31d47070SJunchao Zhang .ve 1094*31d47070SJunchao Zhang 1095*31d47070SJunchao Zhang .N ASYNC_API 1096*31d47070SJunchao Zhang 1097*31d47070SJunchao Zhang .seealso: `PetscDeviceContext` 1098*31d47070SJunchao Zhang @*/ 1099*31d47070SJunchao Zhang PetscErrorCode PetscDeviceContextGetStreamHandle(PetscDeviceContext dctx, void *handle) 1100*31d47070SJunchao Zhang { 1101*31d47070SJunchao Zhang PetscFunctionBegin; 1102*31d47070SJunchao Zhang PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx)); 1103*31d47070SJunchao Zhang PetscValidPointer(handle, 2); 1104*31d47070SJunchao Zhang PetscCall(PetscDeviceContextGetStreamHandle_Internal(dctx, handle)); 1105*31d47070SJunchao Zhang PetscFunctionReturn(PETSC_SUCCESS); 1106*31d47070SJunchao Zhang } 1107