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__)
131c7e414eSJacob 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:
construct_(PetscEvent event) const22089fb57cSJacob 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
destroy_(PetscEvent event) const30089fb57cSJacob 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
reset_(PetscEvent event)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
invalidate_(PetscEvent)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
PetscDeviceContextCreateEvent_Private(PetscDeviceContext dctx,PetscEvent * event)56d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDeviceContextCreateEvent_Private(PetscDeviceContext dctx, PetscEvent *event)
57d71ae5a4SJacob Faibussowitsch {
580e6b6b59SJacob Faibussowitsch PetscFunctionBegin;
590e6b6b59SJacob Faibussowitsch PetscValidDeviceContext(dctx, 1);
604f572ea9SToby Isaac PetscAssertPointer(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
PetscEventDestroy_Private(PetscEvent * event)67d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscEventDestroy_Private(PetscEvent *event)
68d71ae5a4SJacob Faibussowitsch {
690e6b6b59SJacob Faibussowitsch PetscFunctionBegin;
704f572ea9SToby Isaac PetscAssertPointer(event, 1);
71146a86ebSJacob Faibussowitsch if (*event) PetscCall(event_pool.deallocate(event));
723ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
730e6b6b59SJacob Faibussowitsch }
740e6b6b59SJacob Faibussowitsch
PetscDeviceContextRecordEvent_Private(PetscDeviceContext dctx,PetscEvent event)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);
824f572ea9SToby Isaac PetscAssertPointer(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
PetscDeviceContextWaitForEvent_Private(PetscDeviceContext dctx,PetscEvent event)105d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDeviceContextWaitForEvent_Private(PetscDeviceContext dctx, PetscEvent event)
106d71ae5a4SJacob Faibussowitsch {
1070e6b6b59SJacob Faibussowitsch PetscFunctionBegin;
1080e6b6b59SJacob Faibussowitsch PetscValidDeviceContext(dctx, 1);
1094f572ea9SToby Isaac PetscAssertPointer(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
PetscStackFramePetscStackFrame1430e6b6b59SJacob Faibussowitsch PetscStackFrame(const char *file_, const char *func_, int line_) noexcept : file(split_on_petsc_path_(file_)), function(func_), line(line_) { }
1440e6b6b59SJacob Faibussowitsch
operator ==PetscStackFrame1450e6b6b59SJacob Faibussowitsch bool operator==(const PetscStackFrame &other) const noexcept { return line == other.line && file == other.file && function == other.function; }
1460e6b6b59SJacob Faibussowitsch
to_stringPetscStackFrame1477c441f3aSJacob 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:
split_on_petsc_path_PetscStackFrame156d71ae5a4SJacob 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
operator <<(std::ostream & os,const PetscStackFrame & frame)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
swap(PetscStackFrame & lhs,PetscStackFrame & rhs)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>
PetscStackFramePetscStackFrame184d71ae5a4SJacob Faibussowitsch constexpr PetscStackFrame(T &&...) noexcept
185d71ae5a4SJacob Faibussowitsch {
186d71ae5a4SJacob Faibussowitsch }
1870e6b6b59SJacob Faibussowitsch
operator ==PetscStackFrame1880e6b6b59SJacob Faibussowitsch constexpr bool operator==(const PetscStackFrame &) const noexcept { return true; }
1890e6b6b59SJacob Faibussowitsch
to_stringPetscStackFrame1907c441f3aSJacob Faibussowitsch PETSC_NODISCARD static std::string to_string() noexcept { return "(unknown)"; }
1917c441f3aSJacob Faibussowitsch
operator <<(std::ostream & os,const PetscStackFrame &)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
event() const2270e6b6b59SJacob Faibussowitsch PETSC_NODISCARD PetscEvent event() const noexcept { return event_; }
frame() const2280e6b6b59SJacob Faibussowitsch PETSC_NODISCARD const frame_type &frame() const noexcept { return *this; }
frame()2290e6b6b59SJacob Faibussowitsch PETSC_NODISCARD frame_type &frame() noexcept { return *this; }
2307c441f3aSJacob Faibussowitsch
dctx_id() const2317c441f3aSJacob 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
finalize_()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
init_event_(PetscDeviceContext dctx)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
snapshot_type(PetscDeviceContext dctx,frame_type frame)3130e6b6b59SJacob Faibussowitsch MarkedObjectMap::snapshot_type::snapshot_type(PetscDeviceContext dctx, frame_type frame) noexcept : frame_type(std::move(frame)), event_(init_event_(dctx)) { }
3140e6b6b59SJacob Faibussowitsch
~snapshot_type()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
snapshot_type(snapshot_type && other)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
operator =(snapshot_type && other)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
ensure_event(PetscDeviceContext dctx)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
swap(MarkedObjectMap::snapshot_type & lhs,MarkedObjectMap::snapshot_type & rhs)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
PetscGetMarkedObjectMap_Internal(std::size_t * nkeys,PetscObjectId ** keys,PetscMemoryAccessMode ** modes,std::size_t ** ndeps,PetscEvent *** dependencies)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
PetscRestoreMarkedObjectMap_Internal(std::size_t nkeys,PetscObjectId ** keys,PetscMemoryAccessMode ** modes,std::size_t ** ndeps,PetscEvent *** dependencies)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>
PetscDeviceContextMapIterVisitor(PetscDeviceContext dctx,T && callback)391d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDeviceContextMapIterVisitor(PetscDeviceContext dctx, T &&callback) noexcept
392d71ae5a4SJacob Faibussowitsch {
3930e6b6b59SJacob Faibussowitsch const auto dctx_id = PetscObjectCast(dctx)->id;
394dcf958e2SJacob Faibussowitsch auto &&marked = CxxDataCast(dctx)->marked_objects();
3950e6b6b59SJacob Faibussowitsch auto &object_map = marked_object_map.map;
3960e6b6b59SJacob Faibussowitsch
3970e6b6b59SJacob Faibussowitsch PetscFunctionBegin;
398dcf958e2SJacob Faibussowitsch for (auto &&dep : marked) {
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 }
417dcf958e2SJacob Faibussowitsch PetscCallCXX(marked.clear());
4183ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
4190e6b6b59SJacob Faibussowitsch }
4200e6b6b59SJacob Faibussowitsch
PetscDeviceContextSyncClearMap_Internal(PetscDeviceContext dctx)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
446dcf958e2SJacob Faibussowitsch const auto cxx_data = CxxDataCast(dctx);
4470e6b6b59SJacob Faibussowitsch // clang-format off
4480e6b6b59SJacob Faibussowitsch const std::vector<CxxData::upstream_type::value_type> upstream_copy(
449dcf958e2SJacob Faibussowitsch std::make_move_iterator(cxx_data->upstream().begin()),
450dcf958e2SJacob Faibussowitsch std::make_move_iterator(cxx_data->upstream().end())
4510e6b6b59SJacob Faibussowitsch );
4520e6b6b59SJacob Faibussowitsch // clang-format on
4530e6b6b59SJacob Faibussowitsch
4540e6b6b59SJacob Faibussowitsch // aftermath, clear our set of parents (to avoid infinite recursion) and mark ourselves as no
4550e6b6b59SJacob Faibussowitsch // longer contained (while the empty graph technically *is* always contained, it is not what
4560e6b6b59SJacob Faibussowitsch // we mean by it)
457dcf958e2SJacob Faibussowitsch PetscCall(cxx_data->clear());
4580e6b6b59SJacob Faibussowitsch for (auto &&upstrm : upstream_copy) {
459dcf958e2SJacob Faibussowitsch if (const auto udctx = upstrm.second.weak_dctx().lock()) {
4600e6b6b59SJacob Faibussowitsch // check that this parent still points to what we originally thought it was
461dcf958e2SJacob Faibussowitsch PetscCheck(upstrm.first == PetscObjectCast(udctx.get())->id, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Upstream dctx %" PetscInt64_FMT " no longer exists, now has id %" PetscInt64_FMT, upstrm.first, PetscObjectCast(udctx.get())->id);
462dcf958e2SJacob Faibussowitsch PetscCall(PetscDeviceContextSyncClearMap_Internal(udctx.get()));
463dcf958e2SJacob Faibussowitsch }
4640e6b6b59SJacob Faibussowitsch }
4650e6b6b59SJacob Faibussowitsch }
4663ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
4670e6b6b59SJacob Faibussowitsch }
4680e6b6b59SJacob Faibussowitsch
PetscDeviceContextCheckNotOrphaned_Internal(PetscDeviceContext dctx)469d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextCheckNotOrphaned_Internal(PetscDeviceContext dctx)
470d71ae5a4SJacob Faibussowitsch {
4710e6b6b59SJacob Faibussowitsch std::ostringstream oss;
4720e6b6b59SJacob Faibussowitsch //const auto allow = dctx->options.allow_orphans, contained = dctx->contained;
4730e6b6b59SJacob Faibussowitsch const auto allow = true, contained = true;
4740e6b6b59SJacob Faibussowitsch auto wrote_to_oss = false;
4750e6b6b59SJacob Faibussowitsch using map_iterator = MarkedObjectMap::map_type::const_iterator;
4760e6b6b59SJacob Faibussowitsch using dep_iterator = MarkedObjectMap::mapped_type::dependency_type::const_iterator;
4770e6b6b59SJacob Faibussowitsch
4780e6b6b59SJacob Faibussowitsch PetscFunctionBegin;
4790e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextMapIterVisitor(dctx, [&](map_iterator mapit, dep_iterator it, dep_iterator end) {
4800e6b6b59SJacob Faibussowitsch PetscFunctionBegin;
4813ba16761SJacob Faibussowitsch if (allow || contained) PetscFunctionReturn(PETSC_SUCCESS);
4820e6b6b59SJacob Faibussowitsch wrote_to_oss = true;
4830e6b6b59SJacob Faibussowitsch oss << "- PetscObject (id " << mapit->first << "), intent " << PetscMemoryAccessModeToString(mapit->second.mode) << ' ' << it->frame();
4840e6b6b59SJacob Faibussowitsch if (std::distance(it, end) == 0) oss << " (orphaned)"; // we were the only dependency
4850e6b6b59SJacob Faibussowitsch oss << '\n';
4863ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
4870e6b6b59SJacob Faibussowitsch }));
488*00045ab3SPierre Jolivet PetscCheck(!wrote_to_oss, PETSC_COMM_SELF, PETSC_ERR_ORDER, "Destroying PetscDeviceContext ('%s', id %" PetscInt64_FMT ") would leave the following dangling (possibly orphaned) dependents: %s. Must synchronize before destroying it, or allow it to be destroyed with orphans",
4890e6b6b59SJacob Faibussowitsch PetscObjectCast(dctx)->name ? PetscObjectCast(dctx)->name : "unnamed", PetscObjectCast(dctx)->id, oss.str().c_str());
4900e6b6b59SJacob Faibussowitsch PetscCall(CxxDataCast(dctx)->clear());
4913ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
4920e6b6b59SJacob Faibussowitsch }
4930e6b6b59SJacob Faibussowitsch
4947c441f3aSJacob 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__)
4950e6b6b59SJacob Faibussowitsch
4967c441f3aSJacob Faibussowitsch // The current mode is compatible with the previous mode (i.e. read-read) so we need only
4977c441f3aSJacob Faibussowitsch // update the existing version and possibly appeand ourselves to the dependency list
4987c441f3aSJacob Faibussowitsch
4997c441f3aSJacob Faibussowitsch template <bool use_debug>
MarkFromID_CompatibleModes(MarkedObjectMap::mapped_type & marked,PetscDeviceContext dctx,PetscObjectId id,PetscMemoryAccessMode mode,PetscStackFrame<use_debug> & frame,PETSC_UNUSED const char * name,bool * update_object_dependencies)500ce6b3536SJed Brown static PetscErrorCode MarkFromID_CompatibleModes(MarkedObjectMap::mapped_type &marked, PetscDeviceContext dctx, PetscObjectId id, PetscMemoryAccessMode mode, PetscStackFrame<use_debug> &frame, PETSC_UNUSED const char *name, bool *update_object_dependencies)
5017c441f3aSJacob Faibussowitsch {
5027c441f3aSJacob Faibussowitsch const auto dctx_id = PetscObjectCast(dctx)->id;
5037c441f3aSJacob Faibussowitsch auto &object_dependencies = marked.dependencies;
5040e6b6b59SJacob Faibussowitsch const auto end = object_dependencies.end();
5050e6b6b59SJacob Faibussowitsch const auto it = std::find_if(object_dependencies.begin(), end, [&](const MarkedObjectMap::snapshot_type &obj) { return obj.dctx_id() == dctx_id; });
5060e6b6b59SJacob Faibussowitsch
5077c441f3aSJacob Faibussowitsch PetscFunctionBegin;
5087c441f3aSJacob 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)));
5093f7cf3c5SPierre Jolivet (void)mode;
5100e6b6b59SJacob Faibussowitsch if (it != end) {
5117c441f3aSJacob Faibussowitsch using std::swap;
5127c441f3aSJacob Faibussowitsch
5130e6b6b59SJacob Faibussowitsch // we have been here before, all we must do is update our entry then we can bail
5140e6b6b59SJacob Faibussowitsch PetscCall(DEBUG_INFO("found old self as dependency, updating\n"));
515dcf958e2SJacob Faibussowitsch PetscAssert(CxxDataCast(dctx)->has_marked(id), 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);
5167c441f3aSJacob Faibussowitsch swap(it->frame(), frame);
5170e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextRecordEvent_Private(dctx, it->event()));
5187c441f3aSJacob Faibussowitsch *update_object_dependencies = false;
5193ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
5200e6b6b59SJacob Faibussowitsch }
5210e6b6b59SJacob Faibussowitsch
5220e6b6b59SJacob Faibussowitsch // we have not been here before, need to serialize with the last write event (if it exists)
5230e6b6b59SJacob Faibussowitsch // and add ourselves to the dependency list
5240e6b6b59SJacob Faibussowitsch if (const auto event = marked.last_write.event()) PetscCall(PetscDeviceContextWaitForEvent_Private(dctx, event));
5253ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
5267c441f3aSJacob Faibussowitsch }
5277c441f3aSJacob Faibussowitsch
5287c441f3aSJacob Faibussowitsch template <bool use_debug>
MarkFromID_IncompatibleModes_UpdateLastWrite(MarkedObjectMap::mapped_type & marked,PetscDeviceContext dctx,PetscObjectId id,PetscMemoryAccessMode mode,PetscStackFrame<use_debug> & frame,PETSC_UNUSED const char * name,bool * update_object_dependencies)529ce6b3536SJed Brown static PetscErrorCode MarkFromID_IncompatibleModes_UpdateLastWrite(MarkedObjectMap::mapped_type &marked, PetscDeviceContext dctx, PetscObjectId id, PetscMemoryAccessMode mode, PetscStackFrame<use_debug> &frame, PETSC_UNUSED const char *name, bool *update_object_dependencies)
5307c441f3aSJacob Faibussowitsch {
5317c441f3aSJacob Faibussowitsch const auto dctx_id = PetscObjectCast(dctx)->id;
5327c441f3aSJacob Faibussowitsch auto &last_write = marked.last_write;
5337c441f3aSJacob Faibussowitsch auto &last_dep = marked.dependencies.back();
5347c441f3aSJacob Faibussowitsch PetscDeviceType dtype;
5357c441f3aSJacob Faibussowitsch
5367c441f3aSJacob Faibussowitsch PetscFunctionBegin;
5377c441f3aSJacob 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());
5387c441f3aSJacob Faibussowitsch PetscCall(PetscDeviceContextGetDeviceType(dctx, &dtype));
5397c441f3aSJacob Faibussowitsch if (last_dep.event()->dtype != dtype) {
5407c441f3aSJacob Faibussowitsch PetscCall(DEBUG_INFO("moving last write dependency (intent %s)\n", PetscMemoryAccessModeToString(marked.mode)));
5417c441f3aSJacob Faibussowitsch last_write = std::move(last_dep);
5423ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
5437c441f3aSJacob Faibussowitsch }
5447c441f3aSJacob Faibussowitsch
5457c441f3aSJacob Faibussowitsch // we match the device type of the dependency, we can reuse its event!
546dcf958e2SJacob Faibussowitsch const auto cxx_data = CxxDataCast(dctx);
5477c441f3aSJacob Faibussowitsch const auto last_write_was_also_us = last_write.event() && (last_write.dctx_id() == dctx_id);
5487c441f3aSJacob Faibussowitsch using std::swap;
5497c441f3aSJacob Faibussowitsch
5507c441f3aSJacob 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]));
551dcf958e2SJacob Faibussowitsch if (last_dep.event()->dctx_id != dctx_id) PetscCall(cxx_data->add_mark(id));
552dcf958e2SJacob Faibussowitsch PetscAssert(cxx_data->has_marked(id), 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, last_write.frame().to_string().c_str());
5537c441f3aSJacob Faibussowitsch swap(last_write, last_dep);
5547c441f3aSJacob Faibussowitsch if (last_write_was_also_us) {
5557c441f3aSJacob Faibussowitsch PetscCall(DEBUG_INFO("we were also the last write event (intent %s), updating\n", PetscMemoryAccessModeToString(mode)));
5563f7cf3c5SPierre Jolivet (void)mode;
5577c441f3aSJacob Faibussowitsch // we are both the last to write *and* the last to leave a write event. This is the
5587c441f3aSJacob Faibussowitsch // fast path, we only need to update the frame and update the recorded event
5597c441f3aSJacob Faibussowitsch swap(last_dep.frame(), frame);
5607c441f3aSJacob Faibussowitsch // last used to be last_write which is not guaranteed to have an event, so must
5617c441f3aSJacob Faibussowitsch // create it now
5627c441f3aSJacob Faibussowitsch PetscCall(last_dep.ensure_event(dctx));
5637c441f3aSJacob Faibussowitsch PetscCall(PetscDeviceContextRecordEvent_Private(dctx, last_dep.event()));
5647c441f3aSJacob Faibussowitsch *update_object_dependencies = false;
5657c441f3aSJacob Faibussowitsch }
5663ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
5677c441f3aSJacob Faibussowitsch }
5687c441f3aSJacob Faibussowitsch
5697c441f3aSJacob Faibussowitsch // The current mode is NOT compatible with the previous mode. We must serialize with all events
5707c441f3aSJacob Faibussowitsch // in the dependency list, possibly clear it, and update the previous write event
5717c441f3aSJacob Faibussowitsch
5727c441f3aSJacob Faibussowitsch template <bool use_debug>
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 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)
5747c441f3aSJacob Faibussowitsch {
5757c441f3aSJacob Faibussowitsch auto &old_mode = marked.mode;
5767c441f3aSJacob Faibussowitsch auto &object_dependencies = marked.dependencies;
5777c441f3aSJacob Faibussowitsch
5787c441f3aSJacob Faibussowitsch PetscFunctionBegin;
5797c441f3aSJacob Faibussowitsch // we are NOT compatible with the previous mode
5800e6b6b59SJacob 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),
5810e6b6b59SJacob Faibussowitsch object_dependencies.size(), object_dependencies.size() == 1 ? "dependency" : "dependencies"));
5820e6b6b59SJacob Faibussowitsch
5837c441f3aSJacob Faibussowitsch for (const auto &dep : object_dependencies) PetscCall(PetscDeviceContextWaitForEvent_Private(dctx, dep.event()));
5847c441f3aSJacob Faibussowitsch // if the previous mode wrote, update the last write node with it
5857c441f3aSJacob Faibussowitsch if (PetscMemoryAccessWrite(old_mode)) PetscCall(MarkFromID_IncompatibleModes_UpdateLastWrite(marked, dctx, id, mode, frame, name, update_object_dependencies));
5860e6b6b59SJacob Faibussowitsch
5870e6b6b59SJacob Faibussowitsch old_mode = mode;
5887c441f3aSJacob Faibussowitsch // clear out the old dependencies if are about to append ourselves
5897c441f3aSJacob Faibussowitsch if (*update_object_dependencies) object_dependencies.clear();
5903ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
5910e6b6b59SJacob Faibussowitsch }
5927c441f3aSJacob Faibussowitsch
5937c441f3aSJacob Faibussowitsch template <bool use_debug>
PetscDeviceContextMarkIntentFromID_Private(PetscDeviceContext dctx,PetscObjectId id,PetscMemoryAccessMode mode,PetscStackFrame<use_debug> frame,const char * name)5947c441f3aSJacob Faibussowitsch static PetscErrorCode PetscDeviceContextMarkIntentFromID_Private(PetscDeviceContext dctx, PetscObjectId id, PetscMemoryAccessMode mode, PetscStackFrame<use_debug> frame, const char *name)
5957c441f3aSJacob Faibussowitsch {
5967c441f3aSJacob Faibussowitsch auto &marked = marked_object_map.map[id];
5977c441f3aSJacob Faibussowitsch auto &object_dependencies = marked.dependencies;
5987c441f3aSJacob Faibussowitsch auto update_object_dependencies = true;
5997c441f3aSJacob Faibussowitsch
6007c441f3aSJacob Faibussowitsch PetscFunctionBegin;
6017c441f3aSJacob Faibussowitsch if ((marked.mode == PETSC_MEMORY_ACCESS_READ) && (mode == PETSC_MEMORY_ACCESS_READ)) {
6027c441f3aSJacob Faibussowitsch PetscCall(MarkFromID_CompatibleModes(marked, dctx, id, mode, frame, name, &update_object_dependencies));
6037c441f3aSJacob Faibussowitsch } else {
6047c441f3aSJacob Faibussowitsch PetscCall(MarkFromID_IncompatibleModes(marked, dctx, id, mode, frame, name, &update_object_dependencies));
6057c441f3aSJacob Faibussowitsch }
6067c441f3aSJacob Faibussowitsch if (update_object_dependencies) {
6070e6b6b59SJacob Faibussowitsch // become the new leaf by appending ourselves
6080e6b6b59SJacob 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)));
6090e6b6b59SJacob Faibussowitsch PetscCallCXX(object_dependencies.emplace_back(dctx, std::move(frame)));
610dcf958e2SJacob Faibussowitsch PetscCall(CxxDataCast(dctx)->add_mark(id));
6110e6b6b59SJacob Faibussowitsch }
6123ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
6137c441f3aSJacob Faibussowitsch }
6147c441f3aSJacob Faibussowitsch
6157c441f3aSJacob Faibussowitsch #undef DEBUG_INFO
6160e6b6b59SJacob Faibussowitsch
6170e6b6b59SJacob Faibussowitsch /*@C
6180e6b6b59SJacob Faibussowitsch PetscDeviceContextMarkIntentFromID - Indicate a `PetscDeviceContext`s access intent to the
6190e6b6b59SJacob Faibussowitsch auto-dependency system
6200e6b6b59SJacob Faibussowitsch
6210e6b6b59SJacob Faibussowitsch Not Collective
6220e6b6b59SJacob Faibussowitsch
6230e6b6b59SJacob Faibussowitsch Input Parameters:
6240e6b6b59SJacob Faibussowitsch + dctx - The `PetscDeviceContext`
6250e6b6b59SJacob Faibussowitsch . id - The `PetscObjectId` to mark
6260e6b6b59SJacob Faibussowitsch . mode - The desired access intent
6270e6b6b59SJacob Faibussowitsch - name - The object name (for debug purposes, ignored in optimized builds)
6280e6b6b59SJacob Faibussowitsch
6290e6b6b59SJacob Faibussowitsch Notes:
6300e6b6b59SJacob Faibussowitsch This routine formally informs the dependency system that `dctx` will access the object
6310e6b6b59SJacob Faibussowitsch represented by `id` with `mode` and adds `dctx` to `id`'s list of dependencies (termed
6320e6b6b59SJacob Faibussowitsch "leaves").
6330e6b6b59SJacob Faibussowitsch
6340e6b6b59SJacob Faibussowitsch If the existing set of leaves have an incompatible `PetscMemoryAccessMode` to `mode`, `dctx`
6350e6b6b59SJacob Faibussowitsch will be serialized against them.
6360e6b6b59SJacob Faibussowitsch
6370e6b6b59SJacob Faibussowitsch Level: intermediate
6380e6b6b59SJacob Faibussowitsch
6390e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextWaitForContext()`, `PetscDeviceContextSynchronize()`,
6400e6b6b59SJacob Faibussowitsch `PetscObjectGetId()`, `PetscMemoryAccessMode`
6410e6b6b59SJacob Faibussowitsch @*/
PetscDeviceContextMarkIntentFromID(PetscDeviceContext dctx,PetscObjectId id,PetscMemoryAccessMode mode,const char name[])642d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextMarkIntentFromID(PetscDeviceContext dctx, PetscObjectId id, PetscMemoryAccessMode mode, const char name[])
643d71ae5a4SJacob Faibussowitsch {
644dfb7d7afSStefano Zampini #if PetscDefined(USE_DEBUG) && !PetscDefined(HAVE_THREADSAFETY)
6450e6b6b59SJacob Faibussowitsch const auto index = petscstack.currentsize > 2 ? petscstack.currentsize - 2 : 0;
6460e6b6b59SJacob Faibussowitsch const auto file = petscstack.file[index];
6470e6b6b59SJacob Faibussowitsch const auto function = petscstack.function[index];
6480e6b6b59SJacob Faibussowitsch const auto line = petscstack.line[index];
6490e6b6b59SJacob Faibussowitsch #else
6500e6b6b59SJacob Faibussowitsch constexpr const char *file = nullptr;
6510e6b6b59SJacob Faibussowitsch constexpr const char *function = nullptr;
6520e6b6b59SJacob Faibussowitsch constexpr auto line = 0;
6530e6b6b59SJacob Faibussowitsch #endif
6540e6b6b59SJacob Faibussowitsch
6550e6b6b59SJacob Faibussowitsch PetscFunctionBegin;
6560e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
6574f572ea9SToby Isaac if (name) PetscAssertPointer(name, 4);
6580e6b6b59SJacob Faibussowitsch PetscCall(marked_object_map.register_finalize());
6596a4a1270SPierre Jolivet PetscCall(PetscLogEventBegin(DCONTEXT_Mark, dctx, nullptr, nullptr, nullptr));
6600e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextMarkIntentFromID_Private(dctx, id, mode, MarkedObjectMap::snapshot_type::frame_type{file, function, line}, name ? name : "unknown object"));
6616a4a1270SPierre Jolivet PetscCall(PetscLogEventEnd(DCONTEXT_Mark, dctx, nullptr, nullptr, nullptr));
6623ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
6630e6b6b59SJacob Faibussowitsch }
664a8f51744SPierre Jolivet
665a8f51744SPierre Jolivet #if defined(__clang__)
666a8f51744SPierre Jolivet PETSC_PRAGMA_DIAGNOSTIC_IGNORED_END()
667a8f51744SPierre Jolivet #endif
668