10e6b6b59SJacob Faibussowitsch #include "petscdevice_interface_internal.hpp" /*I <petscdevice.h> I*/ 20e6b6b59SJacob Faibussowitsch 30e6b6b59SJacob Faibussowitsch #include <petsc/private/cpp/object_pool.hpp> 40e6b6b59SJacob Faibussowitsch #include <petsc/private/cpp/utility.hpp> 581c64944SJacob Faibussowitsch #include <petsc/private/cpp/unordered_map.hpp> 60e6b6b59SJacob Faibussowitsch 70e6b6b59SJacob Faibussowitsch #include <algorithm> // std::remove_if(), std::find_if() 80e6b6b59SJacob Faibussowitsch #include <vector> 90e6b6b59SJacob Faibussowitsch #include <string> 100e6b6b59SJacob Faibussowitsch #include <sstream> // std::ostringstream 110e6b6b59SJacob Faibussowitsch 12a966a306SPierre Jolivet #if defined(__clang__) 13*1c7e414eSJacob Faibussowitsch PETSC_PRAGMA_DIAGNOSTIC_IGNORED_BEGIN("-Wgnu-zero-variadic-macro-arguments") 14a966a306SPierre Jolivet #endif 15a966a306SPierre Jolivet 160e6b6b59SJacob Faibussowitsch // ========================================================================================== 170e6b6b59SJacob Faibussowitsch // PetscEvent 180e6b6b59SJacob Faibussowitsch // ========================================================================================== 190e6b6b59SJacob Faibussowitsch 20146a86ebSJacob Faibussowitsch class PetscEventConstructor : public Petsc::ConstructorInterface<_n_PetscEvent, PetscEventConstructor> { 21146a86ebSJacob Faibussowitsch public: 22089fb57cSJacob Faibussowitsch PetscErrorCode construct_(PetscEvent event) const noexcept 23d71ae5a4SJacob Faibussowitsch { 240e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 2513bcc0bdSJacob Faibussowitsch PetscCall(PetscMemzero(event, sizeof(*event))); 26146a86ebSJacob Faibussowitsch PetscCall(underlying().reset(event)); 273ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 280e6b6b59SJacob Faibussowitsch } 290e6b6b59SJacob Faibussowitsch 30089fb57cSJacob Faibussowitsch PetscErrorCode destroy_(PetscEvent event) const noexcept 31d71ae5a4SJacob Faibussowitsch { 320e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 33146a86ebSJacob Faibussowitsch PetscCall(underlying().reset(event)); 343ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 350e6b6b59SJacob Faibussowitsch } 360e6b6b59SJacob Faibussowitsch 37089fb57cSJacob Faibussowitsch static PetscErrorCode reset_(PetscEvent event) noexcept 38d71ae5a4SJacob Faibussowitsch { 390e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 400e6b6b59SJacob Faibussowitsch if (auto &destroy = event->destroy) { 410e6b6b59SJacob Faibussowitsch PetscCall((*destroy)(event)); 420e6b6b59SJacob Faibussowitsch destroy = nullptr; 430e6b6b59SJacob Faibussowitsch } 44271378f2SJacob Faibussowitsch PetscAssert(!event->data, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Event failed to destroy its data member: %p", event->data); 450e6b6b59SJacob Faibussowitsch event->dctx_id = 0; 460e6b6b59SJacob Faibussowitsch event->dctx_state = 0; 470e6b6b59SJacob Faibussowitsch event->dtype = PETSC_DEVICE_DEFAULT(); 483ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 490e6b6b59SJacob Faibussowitsch } 50146a86ebSJacob Faibussowitsch 51089fb57cSJacob Faibussowitsch static PetscErrorCode invalidate_(PetscEvent) noexcept { return PETSC_SUCCESS; } 520e6b6b59SJacob Faibussowitsch }; 530e6b6b59SJacob Faibussowitsch 54146a86ebSJacob Faibussowitsch static Petsc::ObjectPool<_n_PetscEvent, PetscEventConstructor> event_pool; 550e6b6b59SJacob Faibussowitsch 56d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDeviceContextCreateEvent_Private(PetscDeviceContext dctx, PetscEvent *event) 57d71ae5a4SJacob Faibussowitsch { 580e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 590e6b6b59SJacob Faibussowitsch PetscValidDeviceContext(dctx, 1); 600e6b6b59SJacob Faibussowitsch PetscValidPointer(event, 2); 610e6b6b59SJacob Faibussowitsch PetscCall(event_pool.allocate(event)); 620e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetDeviceType(dctx, &(*event)->dtype)); 630e6b6b59SJacob Faibussowitsch PetscTryTypeMethod(dctx, createevent, *event); 643ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 650e6b6b59SJacob Faibussowitsch } 660e6b6b59SJacob Faibussowitsch 67d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscEventDestroy_Private(PetscEvent *event) 68d71ae5a4SJacob Faibussowitsch { 690e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 700e6b6b59SJacob Faibussowitsch PetscValidPointer(event, 1); 71146a86ebSJacob Faibussowitsch if (*event) PetscCall(event_pool.deallocate(event)); 723ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 730e6b6b59SJacob Faibussowitsch } 740e6b6b59SJacob Faibussowitsch 75d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDeviceContextRecordEvent_Private(PetscDeviceContext dctx, PetscEvent event) 76d71ae5a4SJacob Faibussowitsch { 770e6b6b59SJacob Faibussowitsch PetscObjectId id; 780e6b6b59SJacob Faibussowitsch PetscObjectState state; 790e6b6b59SJacob Faibussowitsch 800e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 810e6b6b59SJacob Faibussowitsch PetscValidDeviceContext(dctx, 1); 820e6b6b59SJacob Faibussowitsch PetscValidPointer(event, 2); 830e6b6b59SJacob Faibussowitsch id = PetscObjectCast(dctx)->id; 840e6b6b59SJacob Faibussowitsch state = PetscObjectCast(dctx)->state; 850e6b6b59SJacob Faibussowitsch // technically state can never be less than event->dctx_state (only equal) but we include 860e6b6b59SJacob Faibussowitsch // it in the check just in case 873ba16761SJacob Faibussowitsch if ((id == event->dctx_id) && (state <= event->dctx_state)) PetscFunctionReturn(PETSC_SUCCESS); 880e6b6b59SJacob Faibussowitsch if (dctx->ops->recordevent) { 890e6b6b59SJacob Faibussowitsch // REVIEW ME: 900e6b6b59SJacob Faibussowitsch // TODO maybe move this to impls, as they can determine whether they can interoperate with 910e6b6b59SJacob Faibussowitsch // other device types more readily 920e6b6b59SJacob Faibussowitsch if (PetscDefined(USE_DEBUG) && (event->dtype != PETSC_DEVICE_HOST)) { 930e6b6b59SJacob Faibussowitsch PetscDeviceType dtype; 940e6b6b59SJacob Faibussowitsch 950e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetDeviceType(dctx, &dtype)); 960e6b6b59SJacob Faibussowitsch PetscCheck(event->dtype == dtype, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Event type %s does not match device context type %s", PetscDeviceTypes[event->dtype], PetscDeviceTypes[dtype]); 970e6b6b59SJacob Faibussowitsch } 980e6b6b59SJacob Faibussowitsch PetscUseTypeMethod(dctx, recordevent, event); 990e6b6b59SJacob Faibussowitsch } 1000e6b6b59SJacob Faibussowitsch event->dctx_id = id; 1010e6b6b59SJacob Faibussowitsch event->dctx_state = state; 1023ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1030e6b6b59SJacob Faibussowitsch } 1040e6b6b59SJacob Faibussowitsch 105d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDeviceContextWaitForEvent_Private(PetscDeviceContext dctx, PetscEvent event) 106d71ae5a4SJacob Faibussowitsch { 1070e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 1080e6b6b59SJacob Faibussowitsch PetscValidDeviceContext(dctx, 1); 1090e6b6b59SJacob Faibussowitsch PetscValidPointer(event, 2); 1100e6b6b59SJacob Faibussowitsch // empty data implies you cannot wait on this event 1113ba16761SJacob Faibussowitsch if (!event->data) PetscFunctionReturn(PETSC_SUCCESS); 1120e6b6b59SJacob Faibussowitsch if (PetscDefined(USE_DEBUG)) { 1130e6b6b59SJacob Faibussowitsch const auto etype = event->dtype; 1140e6b6b59SJacob Faibussowitsch PetscDeviceType dtype; 1150e6b6b59SJacob Faibussowitsch 1160e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetDeviceType(dctx, &dtype)); 1170e6b6b59SJacob Faibussowitsch PetscCheck(etype == dtype, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Event type %s does not match device context type %s", PetscDeviceTypes[etype], PetscDeviceTypes[dtype]); 1180e6b6b59SJacob Faibussowitsch } 1193ba16761SJacob Faibussowitsch if (PetscObjectCast(dctx)->id == event->dctx_id) PetscFunctionReturn(PETSC_SUCCESS); 1200e6b6b59SJacob Faibussowitsch PetscTryTypeMethod(dctx, waitforevent, event); 1213ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1220e6b6b59SJacob Faibussowitsch } 1230e6b6b59SJacob Faibussowitsch 1240e6b6b59SJacob Faibussowitsch // ========================================================================================== 1250e6b6b59SJacob Faibussowitsch // PetscStackFrame 1260e6b6b59SJacob Faibussowitsch // 1270e6b6b59SJacob Faibussowitsch // A helper class that (when debugging is enabled) contains the stack frame from which 1280e6b6b59SJacob Faibussowitsch // PetscDeviceContextMakrIntentFromID(). It is intended to be derived from, since this enables 1290e6b6b59SJacob Faibussowitsch // empty-base-class optimization to kick in when debugging is disabled. 1300e6b6b59SJacob Faibussowitsch // ========================================================================================== 1310e6b6b59SJacob Faibussowitsch 1320e6b6b59SJacob Faibussowitsch template <bool use_debug> 1330e6b6b59SJacob Faibussowitsch struct PetscStackFrame; 1340e6b6b59SJacob Faibussowitsch 1350e6b6b59SJacob Faibussowitsch template <> 1360e6b6b59SJacob Faibussowitsch struct PetscStackFrame</* use_debug = */ true> { 1370e6b6b59SJacob Faibussowitsch std::string file{}; 1380e6b6b59SJacob Faibussowitsch std::string function{}; 1390e6b6b59SJacob Faibussowitsch int line{}; 1400e6b6b59SJacob Faibussowitsch 1410e6b6b59SJacob Faibussowitsch PetscStackFrame() = default; 1420e6b6b59SJacob Faibussowitsch 1430e6b6b59SJacob Faibussowitsch PetscStackFrame(const char *file_, const char *func_, int line_) noexcept : file(split_on_petsc_path_(file_)), function(func_), line(line_) { } 1440e6b6b59SJacob Faibussowitsch 1450e6b6b59SJacob Faibussowitsch bool operator==(const PetscStackFrame &other) const noexcept { return line == other.line && file == other.file && function == other.function; } 1460e6b6b59SJacob Faibussowitsch 1477c441f3aSJacob Faibussowitsch PETSC_NODISCARD std::string to_string() const noexcept 1487c441f3aSJacob Faibussowitsch { 1497c441f3aSJacob Faibussowitsch std::string ret; 1507c441f3aSJacob Faibussowitsch 1517c441f3aSJacob Faibussowitsch ret = '(' + function + "() at " + file + ':' + std::to_string(line) + ')'; 1527c441f3aSJacob Faibussowitsch return ret; 1537c441f3aSJacob Faibussowitsch } 1547c441f3aSJacob Faibussowitsch 1550e6b6b59SJacob Faibussowitsch private: 156d71ae5a4SJacob Faibussowitsch static std::string split_on_petsc_path_(std::string &&in) noexcept 157d71ae5a4SJacob Faibussowitsch { 1580e6b6b59SJacob Faibussowitsch auto pos = in.find("petsc/src"); 1590e6b6b59SJacob Faibussowitsch 1600e6b6b59SJacob Faibussowitsch if (pos == std::string::npos) pos = in.find("petsc/include"); 1610e6b6b59SJacob Faibussowitsch if (pos == std::string::npos) pos = 0; 1620e6b6b59SJacob Faibussowitsch return in.substr(pos); 1630e6b6b59SJacob Faibussowitsch } 1640e6b6b59SJacob Faibussowitsch 165d71ae5a4SJacob Faibussowitsch friend std::ostream &operator<<(std::ostream &os, const PetscStackFrame &frame) 166d71ae5a4SJacob Faibussowitsch { 1677c441f3aSJacob Faibussowitsch os << frame.to_string(); 1680e6b6b59SJacob Faibussowitsch return os; 1690e6b6b59SJacob Faibussowitsch } 1707c441f3aSJacob Faibussowitsch 1717c441f3aSJacob Faibussowitsch friend void swap(PetscStackFrame &lhs, PetscStackFrame &rhs) noexcept 1727c441f3aSJacob Faibussowitsch { 1737c441f3aSJacob Faibussowitsch using std::swap; 1747c441f3aSJacob Faibussowitsch 1757c441f3aSJacob Faibussowitsch swap(lhs.file, rhs.file); 1767c441f3aSJacob Faibussowitsch swap(lhs.function, rhs.function); 1777c441f3aSJacob Faibussowitsch swap(lhs.line, rhs.line); 1787c441f3aSJacob Faibussowitsch } 1790e6b6b59SJacob Faibussowitsch }; 1800e6b6b59SJacob Faibussowitsch 1810e6b6b59SJacob Faibussowitsch template <> 1820e6b6b59SJacob Faibussowitsch struct PetscStackFrame</* use_debug = */ false> { 1830e6b6b59SJacob Faibussowitsch template <typename... T> 184d71ae5a4SJacob Faibussowitsch constexpr PetscStackFrame(T &&...) noexcept 185d71ae5a4SJacob Faibussowitsch { 186d71ae5a4SJacob Faibussowitsch } 1870e6b6b59SJacob Faibussowitsch 1880e6b6b59SJacob Faibussowitsch constexpr bool operator==(const PetscStackFrame &) const noexcept { return true; } 1890e6b6b59SJacob Faibussowitsch 1907c441f3aSJacob Faibussowitsch PETSC_NODISCARD static std::string to_string() noexcept { return "(unknown)"; } 1917c441f3aSJacob Faibussowitsch 192d71ae5a4SJacob Faibussowitsch friend std::ostream &operator<<(std::ostream &os, const PetscStackFrame &) noexcept 193d71ae5a4SJacob Faibussowitsch { 1940e6b6b59SJacob Faibussowitsch os << "(unknown)"; 1950e6b6b59SJacob Faibussowitsch return os; 1960e6b6b59SJacob Faibussowitsch } 1970e6b6b59SJacob Faibussowitsch }; 1980e6b6b59SJacob Faibussowitsch 1990e6b6b59SJacob Faibussowitsch // ========================================================================================== 2000e6b6b59SJacob Faibussowitsch // MarkedObjectMap 2010e6b6b59SJacob Faibussowitsch // 2020e6b6b59SJacob Faibussowitsch // A mapping from a PetscObjectId to a PetscEvent and (if debugging is enabled) a 2030e6b6b59SJacob Faibussowitsch // PetscStackFrame containing the location where PetscDeviceContextMarkIntentFromID was called 2040e6b6b59SJacob Faibussowitsch // ========================================================================================== 2050e6b6b59SJacob Faibussowitsch 2060e6b6b59SJacob Faibussowitsch class MarkedObjectMap : public Petsc::RegisterFinalizeable<MarkedObjectMap> { 2070e6b6b59SJacob Faibussowitsch public: 2080e6b6b59SJacob Faibussowitsch // Note we derive from PetscStackFrame so that the empty base class optimization can kick 2090e6b6b59SJacob Faibussowitsch // in. If it were just a member it would still take up storage in optimized builds 210dfb7d7afSStefano Zampini class snapshot_type : private PetscStackFrame<PetscDefined(USE_DEBUG) && !PetscDefined(HAVE_THREADSAFETY)> { 2110e6b6b59SJacob Faibussowitsch public: 212dfb7d7afSStefano Zampini using frame_type = PetscStackFrame<PetscDefined(USE_DEBUG) && !PetscDefined(HAVE_THREADSAFETY)>; 2130e6b6b59SJacob Faibussowitsch 2140e6b6b59SJacob Faibussowitsch snapshot_type() = default; 2150e6b6b59SJacob Faibussowitsch snapshot_type(PetscDeviceContext, frame_type) noexcept; 2160e6b6b59SJacob Faibussowitsch 2170e6b6b59SJacob Faibussowitsch ~snapshot_type() noexcept; 2180e6b6b59SJacob Faibussowitsch 2190e6b6b59SJacob Faibussowitsch // movable 2200e6b6b59SJacob Faibussowitsch snapshot_type(snapshot_type &&) noexcept; 2210e6b6b59SJacob Faibussowitsch snapshot_type &operator=(snapshot_type &&) noexcept; 2220e6b6b59SJacob Faibussowitsch 2230e6b6b59SJacob Faibussowitsch // not copyable 2240e6b6b59SJacob Faibussowitsch snapshot_type(const snapshot_type &) noexcept = delete; 2250e6b6b59SJacob Faibussowitsch snapshot_type &operator=(const snapshot_type &) noexcept = delete; 2260e6b6b59SJacob Faibussowitsch 2270e6b6b59SJacob Faibussowitsch PETSC_NODISCARD PetscEvent event() const noexcept { return event_; } 2280e6b6b59SJacob Faibussowitsch PETSC_NODISCARD const frame_type &frame() const noexcept { return *this; } 2290e6b6b59SJacob Faibussowitsch PETSC_NODISCARD frame_type &frame() noexcept { return *this; } 2307c441f3aSJacob Faibussowitsch 2317c441f3aSJacob Faibussowitsch PETSC_NODISCARD PetscObjectId dctx_id() const noexcept 2327c441f3aSJacob Faibussowitsch { 2337c441f3aSJacob Faibussowitsch PetscFunctionBegin; 2347c441f3aSJacob Faibussowitsch PetscAssertAbort(event(), PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Snapshot %s does not contain an event!", frame().to_string().c_str()); 2357c441f3aSJacob Faibussowitsch PetscFunctionReturn(event()->dctx_id); 2367c441f3aSJacob Faibussowitsch } 2377c441f3aSJacob Faibussowitsch 238089fb57cSJacob Faibussowitsch PetscErrorCode ensure_event(PetscDeviceContext) noexcept; 2397c441f3aSJacob Faibussowitsch 2407c441f3aSJacob Faibussowitsch friend void swap(snapshot_type &, snapshot_type &) noexcept; 2410e6b6b59SJacob Faibussowitsch 2420e6b6b59SJacob Faibussowitsch private: 2430e6b6b59SJacob Faibussowitsch PetscEvent event_{}; // the state of device context when this snapshot was recorded 2440e6b6b59SJacob Faibussowitsch 2450e6b6b59SJacob Faibussowitsch PETSC_NODISCARD static PetscEvent init_event_(PetscDeviceContext) noexcept; 2460e6b6b59SJacob Faibussowitsch }; 2470e6b6b59SJacob Faibussowitsch 2480e6b6b59SJacob Faibussowitsch // the "value" each key maps to 2490e6b6b59SJacob Faibussowitsch struct mapped_type { 2500e6b6b59SJacob Faibussowitsch using dependency_type = std::vector<snapshot_type>; 2510e6b6b59SJacob Faibussowitsch 25213bcc0bdSJacob Faibussowitsch mapped_type() noexcept; 2537a798a1aSJacob Faibussowitsch 2547a798a1aSJacob Faibussowitsch PetscMemoryAccessMode mode{PETSC_MEMORY_ACCESS_READ}; 2550e6b6b59SJacob Faibussowitsch snapshot_type last_write{}; 2560e6b6b59SJacob Faibussowitsch dependency_type dependencies{}; 2570e6b6b59SJacob Faibussowitsch }; 2580e6b6b59SJacob Faibussowitsch 25981c64944SJacob Faibussowitsch using map_type = Petsc::UnorderedMap<PetscObjectId, mapped_type>; 2600e6b6b59SJacob Faibussowitsch 2610e6b6b59SJacob Faibussowitsch map_type map; 2620e6b6b59SJacob Faibussowitsch 2630e6b6b59SJacob Faibussowitsch private: 264271378f2SJacob Faibussowitsch friend RegisterFinalizeable; 2650e6b6b59SJacob Faibussowitsch 266089fb57cSJacob Faibussowitsch PetscErrorCode finalize_() noexcept; 2670e6b6b59SJacob Faibussowitsch }; 2680e6b6b59SJacob Faibussowitsch 2690e6b6b59SJacob Faibussowitsch // ========================================================================================== 27013bcc0bdSJacob Faibussowitsch // MarkedObjectMap::mapped_type -- Public API 27113bcc0bdSJacob Faibussowitsch // ========================================================================================== 27213bcc0bdSJacob Faibussowitsch 27313bcc0bdSJacob Faibussowitsch // workaround for clang bug that produces the following warning 27413bcc0bdSJacob Faibussowitsch // 27513bcc0bdSJacob Faibussowitsch // src/sys/objects/device/interface/mark_dcontext.cxx:253:5: error: default member initializer 27613bcc0bdSJacob Faibussowitsch // for 'mode' needed within definition of enclosing class 'MarkedObjectMap' outside of member 27713bcc0bdSJacob Faibussowitsch // functions 27813bcc0bdSJacob Faibussowitsch // mapped_type() noexcept = default; 27913bcc0bdSJacob Faibussowitsch // ^ 28013bcc0bdSJacob Faibussowitsch // https://stackoverflow.com/questions/53408962/try-to-understand-compiler-error-message-default-member-initializer-required-be 28113bcc0bdSJacob Faibussowitsch MarkedObjectMap::mapped_type::mapped_type() noexcept = default; 28213bcc0bdSJacob Faibussowitsch 28313bcc0bdSJacob Faibussowitsch // ========================================================================================== 28481c64944SJacob Faibussowitsch // MarkedObjectMap Private API 2850e6b6b59SJacob Faibussowitsch // ========================================================================================== 2860e6b6b59SJacob Faibussowitsch 287d71ae5a4SJacob Faibussowitsch inline PetscErrorCode MarkedObjectMap::finalize_() noexcept 288d71ae5a4SJacob Faibussowitsch { 2890e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 2900e6b6b59SJacob Faibussowitsch PetscCall(PetscInfo(nullptr, "Finalizing marked object map\n")); 29181c64944SJacob Faibussowitsch PetscCall(map.clear()); 2923ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2930e6b6b59SJacob Faibussowitsch } 2940e6b6b59SJacob Faibussowitsch 2950e6b6b59SJacob Faibussowitsch // ========================================================================================== 29681c64944SJacob Faibussowitsch // MarkedObjectMap::snapshot_type Private API 2970e6b6b59SJacob Faibussowitsch // ========================================================================================== 2980e6b6b59SJacob Faibussowitsch 299d71ae5a4SJacob Faibussowitsch inline PetscEvent MarkedObjectMap::snapshot_type::init_event_(PetscDeviceContext dctx) noexcept 300d71ae5a4SJacob Faibussowitsch { 3010e6b6b59SJacob Faibussowitsch PetscEvent event = nullptr; 3020e6b6b59SJacob Faibussowitsch 3030e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 3040e6b6b59SJacob Faibussowitsch PetscCallAbort(PETSC_COMM_SELF, PetscDeviceContextCreateEvent_Private(dctx, &event)); 3050e6b6b59SJacob Faibussowitsch PetscCallAbort(PETSC_COMM_SELF, PetscDeviceContextRecordEvent_Private(dctx, event)); 3060e6b6b59SJacob Faibussowitsch PetscFunctionReturn(event); 3070e6b6b59SJacob Faibussowitsch } 3080e6b6b59SJacob Faibussowitsch 3090e6b6b59SJacob Faibussowitsch // ========================================================================================== 31081c64944SJacob Faibussowitsch // MarkedObjectMap::snapshot_type Public API 3110e6b6b59SJacob Faibussowitsch // ========================================================================================== 3120e6b6b59SJacob Faibussowitsch 3130e6b6b59SJacob Faibussowitsch MarkedObjectMap::snapshot_type::snapshot_type(PetscDeviceContext dctx, frame_type frame) noexcept : frame_type(std::move(frame)), event_(init_event_(dctx)) { } 3140e6b6b59SJacob Faibussowitsch 315d71ae5a4SJacob Faibussowitsch MarkedObjectMap::snapshot_type::~snapshot_type() noexcept 316d71ae5a4SJacob Faibussowitsch { 3170e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 3180e6b6b59SJacob Faibussowitsch PetscCallAbort(PETSC_COMM_SELF, PetscEventDestroy_Private(&event_)); 3190e6b6b59SJacob Faibussowitsch PetscFunctionReturnVoid(); 3200e6b6b59SJacob Faibussowitsch } 3210e6b6b59SJacob Faibussowitsch 3220e6b6b59SJacob Faibussowitsch // movable 3230e6b6b59SJacob Faibussowitsch MarkedObjectMap::snapshot_type::snapshot_type(snapshot_type &&other) noexcept : frame_type(std::move(other)), event_(Petsc::util::exchange(other.event_, nullptr)) { } 3240e6b6b59SJacob Faibussowitsch 325d71ae5a4SJacob Faibussowitsch MarkedObjectMap::snapshot_type &MarkedObjectMap::snapshot_type::operator=(snapshot_type &&other) noexcept 326d71ae5a4SJacob Faibussowitsch { 3270e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 3280e6b6b59SJacob Faibussowitsch if (this != &other) { 3290e6b6b59SJacob Faibussowitsch frame_type::operator=(std::move(other)); 3300e6b6b59SJacob Faibussowitsch PetscCallAbort(PETSC_COMM_SELF, PetscEventDestroy_Private(&event_)); 3310e6b6b59SJacob Faibussowitsch event_ = Petsc::util::exchange(other.event_, nullptr); 3320e6b6b59SJacob Faibussowitsch } 3330e6b6b59SJacob Faibussowitsch PetscFunctionReturn(*this); 3340e6b6b59SJacob Faibussowitsch } 3350e6b6b59SJacob Faibussowitsch 3367c441f3aSJacob Faibussowitsch PetscErrorCode MarkedObjectMap::snapshot_type::ensure_event(PetscDeviceContext dctx) noexcept 3377c441f3aSJacob Faibussowitsch { 3387c441f3aSJacob Faibussowitsch PetscFunctionBegin; 3397c441f3aSJacob Faibussowitsch if (PetscUnlikely(!event_)) PetscCall(PetscDeviceContextCreateEvent_Private(dctx, &event_)); 3403ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3417c441f3aSJacob Faibussowitsch } 3427c441f3aSJacob Faibussowitsch 3437c441f3aSJacob Faibussowitsch void swap(MarkedObjectMap::snapshot_type &lhs, MarkedObjectMap::snapshot_type &rhs) noexcept 3447c441f3aSJacob Faibussowitsch { 3457c441f3aSJacob Faibussowitsch using std::swap; 3467c441f3aSJacob Faibussowitsch 3477c441f3aSJacob Faibussowitsch swap(lhs.frame(), rhs.frame()); 3487c441f3aSJacob Faibussowitsch swap(lhs.event_, rhs.event_); 3497c441f3aSJacob Faibussowitsch } 3507c441f3aSJacob Faibussowitsch 3510e6b6b59SJacob Faibussowitsch // A mapping between PetscObjectId (i.e. some PetscObject) to the list of PetscEvent's encoding 3520e6b6b59SJacob Faibussowitsch // the last time the PetscObject was accessed 3530e6b6b59SJacob Faibussowitsch static MarkedObjectMap marked_object_map; 3540e6b6b59SJacob Faibussowitsch 3550e6b6b59SJacob Faibussowitsch // ========================================================================================== 3560e6b6b59SJacob Faibussowitsch // Utility Functions 3570e6b6b59SJacob Faibussowitsch // ========================================================================================== 3580e6b6b59SJacob Faibussowitsch 35974f7f6c6SJacob Faibussowitsch PetscErrorCode PetscGetMarkedObjectMap_Internal(std::size_t *nkeys, PetscObjectId **keys, PetscMemoryAccessMode **modes, std::size_t **ndeps, PetscEvent ***dependencies) 36074f7f6c6SJacob Faibussowitsch { 36174f7f6c6SJacob Faibussowitsch std::size_t i = 0; 36274f7f6c6SJacob Faibussowitsch const auto &map = marked_object_map.map; 36374f7f6c6SJacob Faibussowitsch const auto size = *nkeys = map.size(); 36474f7f6c6SJacob Faibussowitsch 36574f7f6c6SJacob Faibussowitsch PetscFunctionBegin; 36674f7f6c6SJacob Faibussowitsch PetscCall(PetscMalloc4(size, keys, size, modes, size, ndeps, size, dependencies)); 36781c64944SJacob Faibussowitsch for (auto it_ = map.begin(); it_ != map.end(); ++it_) { 36881c64944SJacob Faibussowitsch auto &it = *it_; 36974f7f6c6SJacob Faibussowitsch std::size_t j = 0; 37074f7f6c6SJacob Faibussowitsch 37174f7f6c6SJacob Faibussowitsch (*keys)[i] = it.first; 37274f7f6c6SJacob Faibussowitsch (*modes)[i] = it.second.mode; 37374f7f6c6SJacob Faibussowitsch (*ndeps)[i] = it.second.dependencies.size(); 37474f7f6c6SJacob Faibussowitsch (*dependencies)[i] = nullptr; 37574f7f6c6SJacob Faibussowitsch PetscCall(PetscMalloc1((*ndeps)[i], (*dependencies) + i)); 37674f7f6c6SJacob Faibussowitsch for (auto &&dep : it.second.dependencies) (*dependencies)[i][j++] = dep.event(); 37774f7f6c6SJacob Faibussowitsch ++i; 37874f7f6c6SJacob Faibussowitsch } 3793ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 38074f7f6c6SJacob Faibussowitsch } 38174f7f6c6SJacob Faibussowitsch 38274f7f6c6SJacob Faibussowitsch PetscErrorCode PetscRestoreMarkedObjectMap_Internal(std::size_t nkeys, PetscObjectId **keys, PetscMemoryAccessMode **modes, std::size_t **ndeps, PetscEvent ***dependencies) 38374f7f6c6SJacob Faibussowitsch { 38474f7f6c6SJacob Faibussowitsch PetscFunctionBegin; 38574f7f6c6SJacob Faibussowitsch for (std::size_t i = 0; i < nkeys; ++i) PetscCall(PetscFree((*dependencies)[i])); 38674f7f6c6SJacob Faibussowitsch PetscCall(PetscFree4(*keys, *modes, *ndeps, *dependencies)); 3873ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 38874f7f6c6SJacob Faibussowitsch } 38974f7f6c6SJacob Faibussowitsch 3900e6b6b59SJacob Faibussowitsch template <typename T> 391d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDeviceContextMapIterVisitor(PetscDeviceContext dctx, T &&callback) noexcept 392d71ae5a4SJacob Faibussowitsch { 3930e6b6b59SJacob Faibussowitsch const auto dctx_id = PetscObjectCast(dctx)->id; 3940e6b6b59SJacob Faibussowitsch auto &dctx_deps = CxxDataCast(dctx)->deps; 3950e6b6b59SJacob Faibussowitsch auto &object_map = marked_object_map.map; 3960e6b6b59SJacob Faibussowitsch 3970e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 3980e6b6b59SJacob Faibussowitsch for (auto &&dep : dctx_deps) { 3990e6b6b59SJacob Faibussowitsch const auto mapit = object_map.find(dep); 4000e6b6b59SJacob Faibussowitsch 4010e6b6b59SJacob Faibussowitsch // Need this check since the final PetscDeviceContext may run through this *after* the map 4020e6b6b59SJacob Faibussowitsch // has been finalized (and cleared), and hence might fail to find its dependencies. This is 4030e6b6b59SJacob Faibussowitsch // perfectly valid since the user no longer cares about dangling dependencies after PETSc 4040e6b6b59SJacob Faibussowitsch // is finalized 4050e6b6b59SJacob Faibussowitsch if (PetscLikely(mapit != object_map.end())) { 4060e6b6b59SJacob Faibussowitsch auto &deps = mapit->second.dependencies; 4070e6b6b59SJacob Faibussowitsch const auto end = deps.end(); 4080e6b6b59SJacob Faibussowitsch const auto it = std::remove_if(deps.begin(), end, [&](const MarkedObjectMap::snapshot_type &obj) { return obj.dctx_id() == dctx_id; }); 4090e6b6b59SJacob Faibussowitsch 4100e6b6b59SJacob Faibussowitsch PetscCall(callback(mapit, deps.cbegin(), static_cast<decltype(deps.cend())>(it))); 4110e6b6b59SJacob Faibussowitsch // remove ourselves 4120e6b6b59SJacob Faibussowitsch PetscCallCXX(deps.erase(it, end)); 4130e6b6b59SJacob Faibussowitsch // continue to next object, but erase this one if it has no more dependencies 4140e6b6b59SJacob Faibussowitsch if (deps.empty()) PetscCallCXX(object_map.erase(mapit)); 4150e6b6b59SJacob Faibussowitsch } 4160e6b6b59SJacob Faibussowitsch } 4170e6b6b59SJacob Faibussowitsch PetscCallCXX(dctx_deps.clear()); 4183ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 4190e6b6b59SJacob Faibussowitsch } 4200e6b6b59SJacob Faibussowitsch 421d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextSyncClearMap_Internal(PetscDeviceContext dctx) 422d71ae5a4SJacob Faibussowitsch { 4230e6b6b59SJacob Faibussowitsch using map_iterator = MarkedObjectMap::map_type::const_iterator; 4240e6b6b59SJacob Faibussowitsch using dep_iterator = MarkedObjectMap::mapped_type::dependency_type::const_iterator; 4250e6b6b59SJacob Faibussowitsch 4260e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 4270e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextMapIterVisitor(dctx, [&](map_iterator mapit, dep_iterator it, dep_iterator end) { 4280e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 4290e6b6b59SJacob Faibussowitsch if (PetscDefined(USE_DEBUG_AND_INFO)) { 4300e6b6b59SJacob Faibussowitsch std::ostringstream oss; 4310e6b6b59SJacob Faibussowitsch const auto mode = PetscMemoryAccessModeToString(mapit->second.mode); 4320e6b6b59SJacob Faibussowitsch 4330e6b6b59SJacob Faibussowitsch oss << "synced dctx " << PetscObjectCast(dctx)->id << ", remaining leaves for obj " << mapit->first << ": {"; 4340e6b6b59SJacob Faibussowitsch while (it != end) { 4350e6b6b59SJacob Faibussowitsch oss << "[dctx " << it->dctx_id() << ", " << mode << ' ' << it->frame() << ']'; 4360e6b6b59SJacob Faibussowitsch if (++it != end) oss << ", "; 4370e6b6b59SJacob Faibussowitsch } 4380e6b6b59SJacob Faibussowitsch oss << '}'; 4390e6b6b59SJacob Faibussowitsch PetscCall(PetscInfo(nullptr, "%s\n", oss.str().c_str())); 4400e6b6b59SJacob Faibussowitsch } 4413ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 4420e6b6b59SJacob Faibussowitsch })); 4430e6b6b59SJacob Faibussowitsch { 4440e6b6b59SJacob Faibussowitsch // the recursive sync clear map call is unbounded in case of a dependenct loop so we make a 4450e6b6b59SJacob Faibussowitsch // copy 4460e6b6b59SJacob Faibussowitsch // clang-format off 4470e6b6b59SJacob Faibussowitsch const std::vector<CxxData::upstream_type::value_type> upstream_copy( 4480e6b6b59SJacob Faibussowitsch std::make_move_iterator(CxxDataCast(dctx)->upstream.begin()), 4490e6b6b59SJacob Faibussowitsch std::make_move_iterator(CxxDataCast(dctx)->upstream.end()) 4500e6b6b59SJacob Faibussowitsch ); 4510e6b6b59SJacob Faibussowitsch // clang-format on 4520e6b6b59SJacob Faibussowitsch 4530e6b6b59SJacob Faibussowitsch // aftermath, clear our set of parents (to avoid infinite recursion) and mark ourselves as no 4540e6b6b59SJacob Faibussowitsch // longer contained (while the empty graph technically *is* always contained, it is not what 4550e6b6b59SJacob Faibussowitsch // we mean by it) 4560e6b6b59SJacob Faibussowitsch PetscCall(CxxDataCast(dctx)->clear()); 4570e6b6b59SJacob Faibussowitsch //dctx->contained = PETSC_FALSE; 4580e6b6b59SJacob Faibussowitsch for (auto &&upstrm : upstream_copy) { 4590e6b6b59SJacob Faibussowitsch // check that this parent still points to what we originally thought it was 4600e6b6b59SJacob Faibussowitsch PetscCheck(upstrm.second.id == PetscObjectCast(upstrm.first)->id, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Upstream dctx %" PetscInt64_FMT " no longer exists, now has id %" PetscInt64_FMT, upstrm.second.id, PetscObjectCast(upstrm.first)->id); 4610e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextSyncClearMap_Internal(upstrm.first)); 4620e6b6b59SJacob Faibussowitsch } 4630e6b6b59SJacob Faibussowitsch } 4643ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 4650e6b6b59SJacob Faibussowitsch } 4660e6b6b59SJacob Faibussowitsch 467d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextCheckNotOrphaned_Internal(PetscDeviceContext dctx) 468d71ae5a4SJacob Faibussowitsch { 4690e6b6b59SJacob Faibussowitsch std::ostringstream oss; 4700e6b6b59SJacob Faibussowitsch //const auto allow = dctx->options.allow_orphans, contained = dctx->contained; 4710e6b6b59SJacob Faibussowitsch const auto allow = true, contained = true; 4720e6b6b59SJacob Faibussowitsch auto wrote_to_oss = false; 4730e6b6b59SJacob Faibussowitsch using map_iterator = MarkedObjectMap::map_type::const_iterator; 4740e6b6b59SJacob Faibussowitsch using dep_iterator = MarkedObjectMap::mapped_type::dependency_type::const_iterator; 4750e6b6b59SJacob Faibussowitsch 4760e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 4770e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextMapIterVisitor(dctx, [&](map_iterator mapit, dep_iterator it, dep_iterator end) { 4780e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 4793ba16761SJacob Faibussowitsch if (allow || contained) PetscFunctionReturn(PETSC_SUCCESS); 4800e6b6b59SJacob Faibussowitsch wrote_to_oss = true; 4810e6b6b59SJacob Faibussowitsch oss << "- PetscObject (id " << mapit->first << "), intent " << PetscMemoryAccessModeToString(mapit->second.mode) << ' ' << it->frame(); 4820e6b6b59SJacob Faibussowitsch if (std::distance(it, end) == 0) oss << " (orphaned)"; // we were the only dependency 4830e6b6b59SJacob Faibussowitsch oss << '\n'; 4843ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 4850e6b6b59SJacob Faibussowitsch })); 4860e6b6b59SJacob Faibussowitsch PetscCheck(!wrote_to_oss, PETSC_COMM_SELF, PETSC_ERR_ORDER, "Destroying PetscDeviceContext ('%s', id %" PetscInt64_FMT ") would leave the following dangling (possibly orphaned) dependants:\n%s\nMust synchronize before destroying it, or allow it to be destroyed with orphans", 4870e6b6b59SJacob Faibussowitsch PetscObjectCast(dctx)->name ? PetscObjectCast(dctx)->name : "unnamed", PetscObjectCast(dctx)->id, oss.str().c_str()); 4880e6b6b59SJacob Faibussowitsch PetscCall(CxxDataCast(dctx)->clear()); 4893ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 4900e6b6b59SJacob Faibussowitsch } 4910e6b6b59SJacob Faibussowitsch 4927c441f3aSJacob Faibussowitsch #define DEBUG_INFO(mess, ...) PetscDebugInfo(dctx, "dctx %" PetscInt64_FMT " (%s) - obj %" PetscInt64_FMT " (%s): " mess, PetscObjectCast(dctx)->id, PetscObjectCast(dctx)->name ? PetscObjectCast(dctx)->name : "unnamed", id, name, ##__VA_ARGS__) 4930e6b6b59SJacob Faibussowitsch 4947c441f3aSJacob Faibussowitsch // The current mode is compatible with the previous mode (i.e. read-read) so we need only 4957c441f3aSJacob Faibussowitsch // update the existing version and possibly appeand ourselves to the dependency list 4967c441f3aSJacob Faibussowitsch 4977c441f3aSJacob Faibussowitsch template <bool use_debug> 4987c441f3aSJacob Faibussowitsch static PetscErrorCode MarkFromID_CompatibleModes(MarkedObjectMap::mapped_type &marked, PetscDeviceContext dctx, PetscObjectId id, PetscMemoryAccessMode mode, PetscStackFrame<use_debug> &frame, const char *PETSC_UNUSED name, bool *update_object_dependencies) 4997c441f3aSJacob Faibussowitsch { 5007c441f3aSJacob Faibussowitsch const auto dctx_id = PetscObjectCast(dctx)->id; 5017c441f3aSJacob Faibussowitsch auto &object_dependencies = marked.dependencies; 5020e6b6b59SJacob Faibussowitsch const auto end = object_dependencies.end(); 5030e6b6b59SJacob Faibussowitsch const auto it = std::find_if(object_dependencies.begin(), end, [&](const MarkedObjectMap::snapshot_type &obj) { return obj.dctx_id() == dctx_id; }); 5040e6b6b59SJacob Faibussowitsch 5057c441f3aSJacob Faibussowitsch PetscFunctionBegin; 5067c441f3aSJacob Faibussowitsch PetscCall(DEBUG_INFO("new mode (%s) COMPATIBLE with %s mode (%s), no need to serialize\n", PetscMemoryAccessModeToString(mode), object_dependencies.empty() ? "default" : "old", PetscMemoryAccessModeToString(marked.mode))); 5073f7cf3c5SPierre Jolivet (void)mode; 5080e6b6b59SJacob Faibussowitsch if (it != end) { 5097c441f3aSJacob Faibussowitsch using std::swap; 5107c441f3aSJacob Faibussowitsch 5110e6b6b59SJacob Faibussowitsch // we have been here before, all we must do is update our entry then we can bail 5120e6b6b59SJacob Faibussowitsch PetscCall(DEBUG_INFO("found old self as dependency, updating\n")); 5130e6b6b59SJacob Faibussowitsch PetscAssert(CxxDataCast(dctx)->deps.find(id) != CxxDataCast(dctx)->deps.end(), PETSC_COMM_SELF, PETSC_ERR_PLIB, "PetscDeviceContext %" PetscInt64_FMT " listed as dependency for object %" PetscInt64_FMT " (%s), but does not have the object in private dependency list!", dctx_id, id, name); 5147c441f3aSJacob Faibussowitsch swap(it->frame(), frame); 5150e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextRecordEvent_Private(dctx, it->event())); 5167c441f3aSJacob Faibussowitsch *update_object_dependencies = false; 5173ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 5180e6b6b59SJacob Faibussowitsch } 5190e6b6b59SJacob Faibussowitsch 5200e6b6b59SJacob Faibussowitsch // we have not been here before, need to serialize with the last write event (if it exists) 5210e6b6b59SJacob Faibussowitsch // and add ourselves to the dependency list 5220e6b6b59SJacob Faibussowitsch if (const auto event = marked.last_write.event()) PetscCall(PetscDeviceContextWaitForEvent_Private(dctx, event)); 5233ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 5247c441f3aSJacob Faibussowitsch } 5257c441f3aSJacob Faibussowitsch 5267c441f3aSJacob Faibussowitsch template <bool use_debug> 5277c441f3aSJacob Faibussowitsch static PetscErrorCode MarkFromID_IncompatibleModes_UpdateLastWrite(MarkedObjectMap::mapped_type &marked, PetscDeviceContext dctx, PetscObjectId id, PetscMemoryAccessMode mode, PetscStackFrame<use_debug> &frame, const char *PETSC_UNUSED name, bool *update_object_dependencies) 5287c441f3aSJacob Faibussowitsch { 5297c441f3aSJacob Faibussowitsch const auto dctx_id = PetscObjectCast(dctx)->id; 5307c441f3aSJacob Faibussowitsch auto &last_write = marked.last_write; 5317c441f3aSJacob Faibussowitsch auto &last_dep = marked.dependencies.back(); 5327c441f3aSJacob Faibussowitsch PetscDeviceType dtype; 5337c441f3aSJacob Faibussowitsch 5347c441f3aSJacob Faibussowitsch PetscFunctionBegin; 5357c441f3aSJacob Faibussowitsch PetscAssert(marked.dependencies.size() == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Can only have a single writer as dependency, have %zu!", marked.dependencies.size()); 5367c441f3aSJacob Faibussowitsch PetscCall(PetscDeviceContextGetDeviceType(dctx, &dtype)); 5377c441f3aSJacob Faibussowitsch if (last_dep.event()->dtype != dtype) { 5387c441f3aSJacob Faibussowitsch PetscCall(DEBUG_INFO("moving last write dependency (intent %s)\n", PetscMemoryAccessModeToString(marked.mode))); 5397c441f3aSJacob Faibussowitsch last_write = std::move(last_dep); 5403ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 5417c441f3aSJacob Faibussowitsch } 5427c441f3aSJacob Faibussowitsch 5437c441f3aSJacob Faibussowitsch // we match the device type of the dependency, we can reuse its event! 5447c441f3aSJacob Faibussowitsch auto &dctx_upstream_deps = CxxDataCast(dctx)->deps; 5457c441f3aSJacob Faibussowitsch const auto last_write_was_also_us = last_write.event() && (last_write.dctx_id() == dctx_id); 5467c441f3aSJacob Faibussowitsch using std::swap; 5477c441f3aSJacob Faibussowitsch 5487c441f3aSJacob Faibussowitsch PetscCall(DEBUG_INFO("we matched the previous write dependency's (intent %s) device type (%s), swapping last dependency with last write\n", PetscMemoryAccessModeToString(marked.mode), PetscDeviceTypes[dtype])); 5497c441f3aSJacob Faibussowitsch if (last_dep.event()->dctx_id != dctx_id) dctx_upstream_deps.emplace(id); 5507c441f3aSJacob Faibussowitsch PetscAssert(dctx_upstream_deps.find(id) != dctx_upstream_deps.end(), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Did not find id %" PetscInt64_FMT "in object dependencies, but we have apparently recorded the last dependency %s!", id, 5517c441f3aSJacob Faibussowitsch last_write.frame().to_string().c_str()); 5527c441f3aSJacob Faibussowitsch swap(last_write, last_dep); 5537c441f3aSJacob Faibussowitsch if (last_write_was_also_us) { 5547c441f3aSJacob Faibussowitsch PetscCall(DEBUG_INFO("we were also the last write event (intent %s), updating\n", PetscMemoryAccessModeToString(mode))); 5553f7cf3c5SPierre Jolivet (void)mode; 5567c441f3aSJacob Faibussowitsch // we are both the last to write *and* the last to leave a write event. This is the 5577c441f3aSJacob Faibussowitsch // fast path, we only need to update the frame and update the recorded event 5587c441f3aSJacob Faibussowitsch swap(last_dep.frame(), frame); 5597c441f3aSJacob Faibussowitsch // last used to be last_write which is not guaranteed to have an event, so must 5607c441f3aSJacob Faibussowitsch // create it now 5617c441f3aSJacob Faibussowitsch PetscCall(last_dep.ensure_event(dctx)); 5627c441f3aSJacob Faibussowitsch PetscCall(PetscDeviceContextRecordEvent_Private(dctx, last_dep.event())); 5637c441f3aSJacob Faibussowitsch *update_object_dependencies = false; 5647c441f3aSJacob Faibussowitsch } 5653ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 5667c441f3aSJacob Faibussowitsch } 5677c441f3aSJacob Faibussowitsch 5687c441f3aSJacob Faibussowitsch // The current mode is NOT compatible with the previous mode. We must serialize with all events 5697c441f3aSJacob Faibussowitsch // in the dependency list, possibly clear it, and update the previous write event 5707c441f3aSJacob Faibussowitsch 5717c441f3aSJacob Faibussowitsch template <bool use_debug> 5727c441f3aSJacob Faibussowitsch static PetscErrorCode MarkFromID_IncompatibleModes(MarkedObjectMap::mapped_type &marked, PetscDeviceContext dctx, PetscObjectId id, PetscMemoryAccessMode mode, PetscStackFrame<use_debug> &frame, const char *name, bool *update_object_dependencies) 5737c441f3aSJacob Faibussowitsch { 5747c441f3aSJacob Faibussowitsch auto &old_mode = marked.mode; 5757c441f3aSJacob Faibussowitsch auto &object_dependencies = marked.dependencies; 5767c441f3aSJacob Faibussowitsch 5777c441f3aSJacob Faibussowitsch PetscFunctionBegin; 5787c441f3aSJacob Faibussowitsch // we are NOT compatible with the previous mode 5790e6b6b59SJacob Faibussowitsch PetscCall(DEBUG_INFO("new mode (%s) NOT COMPATIBLE with %s mode (%s), serializing then clearing (%zu) %s\n", PetscMemoryAccessModeToString(mode), object_dependencies.empty() ? "default" : "old", PetscMemoryAccessModeToString(old_mode), 5800e6b6b59SJacob Faibussowitsch object_dependencies.size(), object_dependencies.size() == 1 ? "dependency" : "dependencies")); 5810e6b6b59SJacob Faibussowitsch 5827c441f3aSJacob Faibussowitsch for (const auto &dep : object_dependencies) PetscCall(PetscDeviceContextWaitForEvent_Private(dctx, dep.event())); 5837c441f3aSJacob Faibussowitsch // if the previous mode wrote, update the last write node with it 5847c441f3aSJacob Faibussowitsch if (PetscMemoryAccessWrite(old_mode)) PetscCall(MarkFromID_IncompatibleModes_UpdateLastWrite(marked, dctx, id, mode, frame, name, update_object_dependencies)); 5850e6b6b59SJacob Faibussowitsch 5860e6b6b59SJacob Faibussowitsch old_mode = mode; 5877c441f3aSJacob Faibussowitsch // clear out the old dependencies if are about to append ourselves 5887c441f3aSJacob Faibussowitsch if (*update_object_dependencies) object_dependencies.clear(); 5893ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 5900e6b6b59SJacob Faibussowitsch } 5917c441f3aSJacob Faibussowitsch 5927c441f3aSJacob Faibussowitsch template <bool use_debug> 5937c441f3aSJacob Faibussowitsch static PetscErrorCode PetscDeviceContextMarkIntentFromID_Private(PetscDeviceContext dctx, PetscObjectId id, PetscMemoryAccessMode mode, PetscStackFrame<use_debug> frame, const char *name) 5947c441f3aSJacob Faibussowitsch { 5957c441f3aSJacob Faibussowitsch auto &marked = marked_object_map.map[id]; 5967c441f3aSJacob Faibussowitsch auto &object_dependencies = marked.dependencies; 5977c441f3aSJacob Faibussowitsch auto update_object_dependencies = true; 5987c441f3aSJacob Faibussowitsch 5997c441f3aSJacob Faibussowitsch PetscFunctionBegin; 6007c441f3aSJacob Faibussowitsch if ((marked.mode == PETSC_MEMORY_ACCESS_READ) && (mode == PETSC_MEMORY_ACCESS_READ)) { 6017c441f3aSJacob Faibussowitsch PetscCall(MarkFromID_CompatibleModes(marked, dctx, id, mode, frame, name, &update_object_dependencies)); 6027c441f3aSJacob Faibussowitsch } else { 6037c441f3aSJacob Faibussowitsch PetscCall(MarkFromID_IncompatibleModes(marked, dctx, id, mode, frame, name, &update_object_dependencies)); 6047c441f3aSJacob Faibussowitsch } 6057c441f3aSJacob Faibussowitsch if (update_object_dependencies) { 6060e6b6b59SJacob Faibussowitsch // become the new leaf by appending ourselves 6070e6b6b59SJacob Faibussowitsch PetscCall(DEBUG_INFO("%s with intent %s\n", object_dependencies.empty() ? "dependency list is empty, creating new leaf" : "appending to existing leaves", PetscMemoryAccessModeToString(mode))); 6080e6b6b59SJacob Faibussowitsch PetscCallCXX(object_dependencies.emplace_back(dctx, std::move(frame))); 6090e6b6b59SJacob Faibussowitsch PetscCallCXX(CxxDataCast(dctx)->deps.emplace(id)); 6100e6b6b59SJacob Faibussowitsch } 6113ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 6127c441f3aSJacob Faibussowitsch } 6137c441f3aSJacob Faibussowitsch 6147c441f3aSJacob Faibussowitsch #undef DEBUG_INFO 6150e6b6b59SJacob Faibussowitsch 6160e6b6b59SJacob Faibussowitsch /*@C 6170e6b6b59SJacob Faibussowitsch PetscDeviceContextMarkIntentFromID - Indicate a `PetscDeviceContext`s access intent to the 6180e6b6b59SJacob Faibussowitsch auto-dependency system 6190e6b6b59SJacob Faibussowitsch 6200e6b6b59SJacob Faibussowitsch Not Collective 6210e6b6b59SJacob Faibussowitsch 6220e6b6b59SJacob Faibussowitsch Input Parameters: 6230e6b6b59SJacob Faibussowitsch + dctx - The `PetscDeviceContext` 6240e6b6b59SJacob Faibussowitsch . id - The `PetscObjectId` to mark 6250e6b6b59SJacob Faibussowitsch . mode - The desired access intent 6260e6b6b59SJacob Faibussowitsch - name - The object name (for debug purposes, ignored in optimized builds) 6270e6b6b59SJacob Faibussowitsch 6280e6b6b59SJacob Faibussowitsch Notes: 6290e6b6b59SJacob Faibussowitsch This routine formally informs the dependency system that `dctx` will access the object 6300e6b6b59SJacob Faibussowitsch represented by `id` with `mode` and adds `dctx` to `id`'s list of dependencies (termed 6310e6b6b59SJacob Faibussowitsch "leaves"). 6320e6b6b59SJacob Faibussowitsch 6330e6b6b59SJacob Faibussowitsch If the existing set of leaves have an incompatible `PetscMemoryAccessMode` to `mode`, `dctx` 6340e6b6b59SJacob Faibussowitsch will be serialized against them. 6350e6b6b59SJacob Faibussowitsch 6360e6b6b59SJacob Faibussowitsch Level: intermediate 6370e6b6b59SJacob Faibussowitsch 6380e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextWaitForContext()`, `PetscDeviceContextSynchronize()`, 6390e6b6b59SJacob Faibussowitsch `PetscObjectGetId()`, `PetscMemoryAccessMode` 6400e6b6b59SJacob Faibussowitsch @*/ 641d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextMarkIntentFromID(PetscDeviceContext dctx, PetscObjectId id, PetscMemoryAccessMode mode, const char name[]) 642d71ae5a4SJacob Faibussowitsch { 643dfb7d7afSStefano Zampini #if PetscDefined(USE_DEBUG) && !PetscDefined(HAVE_THREADSAFETY) 6440e6b6b59SJacob Faibussowitsch const auto index = petscstack.currentsize > 2 ? petscstack.currentsize - 2 : 0; 6450e6b6b59SJacob Faibussowitsch const auto file = petscstack.file[index]; 6460e6b6b59SJacob Faibussowitsch const auto function = petscstack.function[index]; 6470e6b6b59SJacob Faibussowitsch const auto line = petscstack.line[index]; 6480e6b6b59SJacob Faibussowitsch #else 6490e6b6b59SJacob Faibussowitsch constexpr const char *file = nullptr; 6500e6b6b59SJacob Faibussowitsch constexpr const char *function = nullptr; 6510e6b6b59SJacob Faibussowitsch constexpr auto line = 0; 6520e6b6b59SJacob Faibussowitsch #endif 6530e6b6b59SJacob Faibussowitsch 6540e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 6550e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx)); 6560e6b6b59SJacob Faibussowitsch if (name) PetscValidCharPointer(name, 4); 6570e6b6b59SJacob Faibussowitsch PetscCall(marked_object_map.register_finalize()); 6586a4a1270SPierre Jolivet PetscCall(PetscLogEventBegin(DCONTEXT_Mark, dctx, nullptr, nullptr, nullptr)); 6590e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextMarkIntentFromID_Private(dctx, id, mode, MarkedObjectMap::snapshot_type::frame_type{file, function, line}, name ? name : "unknown object")); 6606a4a1270SPierre Jolivet PetscCall(PetscLogEventEnd(DCONTEXT_Mark, dctx, nullptr, nullptr, nullptr)); 6613ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 6620e6b6b59SJacob Faibussowitsch } 663