xref: /petsc/src/sys/objects/device/interface/mark_dcontext.cxx (revision d71ae5a4db6382e7f06317b8d368875286fe9008)
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>
50e6b6b59SJacob Faibussowitsch 
60e6b6b59SJacob Faibussowitsch #include <unordered_map>
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__)
13a966a306SPierre Jolivet   #pragma clang diagnostic push
14a966a306SPierre Jolivet   #pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
15a966a306SPierre Jolivet #endif
16a966a306SPierre Jolivet 
170e6b6b59SJacob Faibussowitsch // ==========================================================================================
180e6b6b59SJacob Faibussowitsch // PetscEvent
190e6b6b59SJacob Faibussowitsch // ==========================================================================================
200e6b6b59SJacob Faibussowitsch 
210e6b6b59SJacob Faibussowitsch struct PetscEventAllocator : public Petsc::AllocatorBase<PetscEvent> {
22*d71ae5a4SJacob Faibussowitsch   PETSC_NODISCARD static PetscErrorCode create(PetscEvent *event) noexcept
23*d71ae5a4SJacob Faibussowitsch   {
240e6b6b59SJacob Faibussowitsch     PetscFunctionBegin;
250e6b6b59SJacob Faibussowitsch     PetscCall(PetscNew(event));
260e6b6b59SJacob Faibussowitsch     PetscFunctionReturn(0);
270e6b6b59SJacob Faibussowitsch   }
280e6b6b59SJacob Faibussowitsch 
29*d71ae5a4SJacob Faibussowitsch   PETSC_NODISCARD static PetscErrorCode destroy(PetscEvent event) noexcept
30*d71ae5a4SJacob Faibussowitsch   {
310e6b6b59SJacob Faibussowitsch     PetscFunctionBegin;
320e6b6b59SJacob Faibussowitsch     PetscCall(reset(event));
330e6b6b59SJacob Faibussowitsch     PetscCall(PetscFree(event));
340e6b6b59SJacob Faibussowitsch     PetscFunctionReturn(0);
350e6b6b59SJacob Faibussowitsch   }
360e6b6b59SJacob Faibussowitsch 
37*d71ae5a4SJacob Faibussowitsch   PETSC_NODISCARD static PetscErrorCode reset(PetscEvent event, bool zero = true) noexcept
38*d71ae5a4SJacob Faibussowitsch   {
390e6b6b59SJacob Faibussowitsch     PetscFunctionBegin;
400e6b6b59SJacob Faibussowitsch     if (zero) {
410e6b6b59SJacob Faibussowitsch       if (auto &destroy = event->destroy) {
420e6b6b59SJacob Faibussowitsch         PetscCall((*destroy)(event));
430e6b6b59SJacob Faibussowitsch         destroy = nullptr;
440e6b6b59SJacob Faibussowitsch       }
450e6b6b59SJacob Faibussowitsch       event->dctx_id    = 0;
460e6b6b59SJacob Faibussowitsch       event->dctx_state = 0;
470e6b6b59SJacob Faibussowitsch       PetscAssert(!event->data, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Event failed to destroy its data member: %p", event->data);
480e6b6b59SJacob Faibussowitsch     }
490e6b6b59SJacob Faibussowitsch     event->dtype = PETSC_DEVICE_DEFAULT();
500e6b6b59SJacob Faibussowitsch     PetscFunctionReturn(0);
510e6b6b59SJacob Faibussowitsch   }
520e6b6b59SJacob Faibussowitsch };
530e6b6b59SJacob Faibussowitsch 
540e6b6b59SJacob Faibussowitsch static Petsc::ObjectPool<PetscEvent, PetscEventAllocator> event_pool;
550e6b6b59SJacob Faibussowitsch 
56*d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDeviceContextCreateEvent_Private(PetscDeviceContext dctx, PetscEvent *event)
57*d71ae5a4SJacob 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);
640e6b6b59SJacob Faibussowitsch   PetscFunctionReturn(0);
650e6b6b59SJacob Faibussowitsch }
660e6b6b59SJacob Faibussowitsch 
67*d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscEventDestroy_Private(PetscEvent *event)
68*d71ae5a4SJacob Faibussowitsch {
690e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
700e6b6b59SJacob Faibussowitsch   PetscValidPointer(event, 1);
710e6b6b59SJacob Faibussowitsch   if (*event) PetscCall(event_pool.deallocate(Petsc::util::exchange(*event, nullptr)));
720e6b6b59SJacob Faibussowitsch   PetscFunctionReturn(0);
730e6b6b59SJacob Faibussowitsch }
740e6b6b59SJacob Faibussowitsch 
75*d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDeviceContextRecordEvent_Private(PetscDeviceContext dctx, PetscEvent event)
76*d71ae5a4SJacob 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
870e6b6b59SJacob Faibussowitsch   if ((id == event->dctx_id) && (state <= event->dctx_state)) PetscFunctionReturn(0);
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;
1020e6b6b59SJacob Faibussowitsch   PetscFunctionReturn(0);
1030e6b6b59SJacob Faibussowitsch }
1040e6b6b59SJacob Faibussowitsch 
105*d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDeviceContextWaitForEvent_Private(PetscDeviceContext dctx, PetscEvent event)
106*d71ae5a4SJacob 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
1110e6b6b59SJacob Faibussowitsch   if (!event->data) PetscFunctionReturn(0);
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   }
1190e6b6b59SJacob Faibussowitsch   if (PetscObjectCast(dctx)->id == event->dctx_id) PetscFunctionReturn(0);
1200e6b6b59SJacob Faibussowitsch   PetscTryTypeMethod(dctx, waitforevent, event);
1210e6b6b59SJacob Faibussowitsch   PetscFunctionReturn(0);
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 
1470e6b6b59SJacob Faibussowitsch private:
148*d71ae5a4SJacob Faibussowitsch   static std::string split_on_petsc_path_(std::string &&in) noexcept
149*d71ae5a4SJacob Faibussowitsch   {
1500e6b6b59SJacob Faibussowitsch     auto pos = in.find("petsc/src");
1510e6b6b59SJacob Faibussowitsch 
1520e6b6b59SJacob Faibussowitsch     if (pos == std::string::npos) pos = in.find("petsc/include");
1530e6b6b59SJacob Faibussowitsch     if (pos == std::string::npos) pos = 0;
1540e6b6b59SJacob Faibussowitsch     return in.substr(pos);
1550e6b6b59SJacob Faibussowitsch   }
1560e6b6b59SJacob Faibussowitsch 
157*d71ae5a4SJacob Faibussowitsch   friend std::ostream &operator<<(std::ostream &os, const PetscStackFrame &frame)
158*d71ae5a4SJacob Faibussowitsch   {
1590e6b6b59SJacob Faibussowitsch     os << '(' << frame.function << "() at " << frame.file << ':' << frame.line << ')';
1600e6b6b59SJacob Faibussowitsch     return os;
1610e6b6b59SJacob Faibussowitsch   }
1620e6b6b59SJacob Faibussowitsch };
1630e6b6b59SJacob Faibussowitsch 
1640e6b6b59SJacob Faibussowitsch template <>
1650e6b6b59SJacob Faibussowitsch struct PetscStackFrame</* use_debug = */ false> {
1660e6b6b59SJacob Faibussowitsch   template <typename... T>
167*d71ae5a4SJacob Faibussowitsch   constexpr PetscStackFrame(T &&...) noexcept
168*d71ae5a4SJacob Faibussowitsch   {
169*d71ae5a4SJacob Faibussowitsch   }
1700e6b6b59SJacob Faibussowitsch 
1710e6b6b59SJacob Faibussowitsch   constexpr bool operator==(const PetscStackFrame &) const noexcept { return true; }
1720e6b6b59SJacob Faibussowitsch 
173*d71ae5a4SJacob Faibussowitsch   friend std::ostream &operator<<(std::ostream &os, const PetscStackFrame &) noexcept
174*d71ae5a4SJacob Faibussowitsch   {
1750e6b6b59SJacob Faibussowitsch     os << "(unknown)";
1760e6b6b59SJacob Faibussowitsch     return os;
1770e6b6b59SJacob Faibussowitsch   }
1780e6b6b59SJacob Faibussowitsch };
1790e6b6b59SJacob Faibussowitsch 
1800e6b6b59SJacob Faibussowitsch // ==========================================================================================
1810e6b6b59SJacob Faibussowitsch // MarkedObjectMap
1820e6b6b59SJacob Faibussowitsch //
1830e6b6b59SJacob Faibussowitsch // A mapping from a PetscObjectId to a PetscEvent and (if debugging is enabled) a
1840e6b6b59SJacob Faibussowitsch // PetscStackFrame containing the location where PetscDeviceContextMarkIntentFromID was called
1850e6b6b59SJacob Faibussowitsch // ==========================================================================================
1860e6b6b59SJacob Faibussowitsch 
1870e6b6b59SJacob Faibussowitsch class MarkedObjectMap : public Petsc::RegisterFinalizeable<MarkedObjectMap> {
1880e6b6b59SJacob Faibussowitsch public:
1890e6b6b59SJacob Faibussowitsch   // Note we derive from PetscStackFrame so that the empty base class optimization can kick
1900e6b6b59SJacob Faibussowitsch   // in. If it were just a member it would still take up storage in optimized builds
1910e6b6b59SJacob Faibussowitsch   class snapshot_type : private PetscStackFrame<PetscDefined(USE_DEBUG)> {
1920e6b6b59SJacob Faibussowitsch   public:
1930e6b6b59SJacob Faibussowitsch     using frame_type = PetscStackFrame<PetscDefined(USE_DEBUG)>;
1940e6b6b59SJacob Faibussowitsch 
1950e6b6b59SJacob Faibussowitsch     snapshot_type() = default;
1960e6b6b59SJacob Faibussowitsch     snapshot_type(PetscDeviceContext, frame_type) noexcept;
1970e6b6b59SJacob Faibussowitsch 
1980e6b6b59SJacob Faibussowitsch     ~snapshot_type() noexcept;
1990e6b6b59SJacob Faibussowitsch 
2000e6b6b59SJacob Faibussowitsch     // movable
2010e6b6b59SJacob Faibussowitsch     snapshot_type(snapshot_type &&) noexcept;
2020e6b6b59SJacob Faibussowitsch     snapshot_type &operator=(snapshot_type &&) noexcept;
2030e6b6b59SJacob Faibussowitsch 
2040e6b6b59SJacob Faibussowitsch     // not copyable
2050e6b6b59SJacob Faibussowitsch     snapshot_type(const snapshot_type &) noexcept            = delete;
2060e6b6b59SJacob Faibussowitsch     snapshot_type &operator=(const snapshot_type &) noexcept = delete;
2070e6b6b59SJacob Faibussowitsch 
2080e6b6b59SJacob Faibussowitsch     PETSC_NODISCARD PetscEvent        event() const noexcept { return event_; }
2090e6b6b59SJacob Faibussowitsch     PETSC_NODISCARD const frame_type &frame() const noexcept { return *this; }
2100e6b6b59SJacob Faibussowitsch     PETSC_NODISCARD frame_type       &frame() noexcept { return *this; }
2110e6b6b59SJacob Faibussowitsch     PETSC_NODISCARD PetscObjectId     dctx_id() const noexcept { return event()->dctx_id; }
2120e6b6b59SJacob Faibussowitsch 
2130e6b6b59SJacob Faibussowitsch   private:
2140e6b6b59SJacob Faibussowitsch     PetscEvent event_{}; // the state of device context when this snapshot was recorded
2150e6b6b59SJacob Faibussowitsch 
2160e6b6b59SJacob Faibussowitsch     PETSC_NODISCARD static PetscEvent init_event_(PetscDeviceContext) noexcept;
2170e6b6b59SJacob Faibussowitsch   };
2180e6b6b59SJacob Faibussowitsch 
2190e6b6b59SJacob Faibussowitsch   // the "value" each key maps to
2200e6b6b59SJacob Faibussowitsch   struct mapped_type {
2210e6b6b59SJacob Faibussowitsch     using dependency_type = std::vector<snapshot_type>;
2220e6b6b59SJacob Faibussowitsch 
2230e6b6b59SJacob Faibussowitsch     PetscMemoryAccessMode mode = PETSC_MEMORY_ACCESS_READ;
2240e6b6b59SJacob Faibussowitsch     snapshot_type         last_write{};
2250e6b6b59SJacob Faibussowitsch     dependency_type       dependencies{};
2260e6b6b59SJacob Faibussowitsch   };
2270e6b6b59SJacob Faibussowitsch 
2280e6b6b59SJacob Faibussowitsch   using map_type = std::unordered_map<PetscObjectId, mapped_type>;
2290e6b6b59SJacob Faibussowitsch 
2300e6b6b59SJacob Faibussowitsch   map_type map;
2310e6b6b59SJacob Faibussowitsch 
2320e6b6b59SJacob Faibussowitsch private:
2330e6b6b59SJacob Faibussowitsch   friend class RegisterFinalizeable<MarkedObjectMap>;
2340e6b6b59SJacob Faibussowitsch 
2350e6b6b59SJacob Faibussowitsch   PETSC_NODISCARD PetscErrorCode finalize_() noexcept;
2360e6b6b59SJacob Faibussowitsch };
2370e6b6b59SJacob Faibussowitsch 
2380e6b6b59SJacob Faibussowitsch // ==========================================================================================
2390e6b6b59SJacob Faibussowitsch // MarkedObejctMap Private API
2400e6b6b59SJacob Faibussowitsch // ==========================================================================================
2410e6b6b59SJacob Faibussowitsch 
242*d71ae5a4SJacob Faibussowitsch inline PetscErrorCode MarkedObjectMap::finalize_() noexcept
243*d71ae5a4SJacob Faibussowitsch {
2440e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
2450e6b6b59SJacob Faibussowitsch   PetscCall(PetscInfo(nullptr, "Finalizing marked object map\n"));
2460e6b6b59SJacob Faibussowitsch   if (PetscDefined(USE_DEBUG)) {
2470e6b6b59SJacob Faibussowitsch     std::ostringstream oss;
2480e6b6b59SJacob Faibussowitsch     auto               wrote_to_oss = false;
2490e6b6b59SJacob Faibussowitsch     const auto         end          = this->map.cend();
2500e6b6b59SJacob Faibussowitsch     PetscMPIInt        rank;
2510e6b6b59SJacob Faibussowitsch 
2520e6b6b59SJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
2530e6b6b59SJacob Faibussowitsch     for (auto it = this->map.cbegin(); it != end; ++it) {
2540e6b6b59SJacob Faibussowitsch       // need a temporary since we want to prepend "object xxx has orphaned dependencies" if
2550e6b6b59SJacob Faibussowitsch       // any of the dependencies have orphans. but we also need to check that in the loop, so
2560e6b6b59SJacob Faibussowitsch       // use a temporary to accumulate and then build the rest from it.
2570e6b6b59SJacob Faibussowitsch       std::ostringstream oss_tmp;
2580e6b6b59SJacob Faibussowitsch       auto               wrote_to_oss_tmp = false;
2590e6b6b59SJacob Faibussowitsch       //const auto        &mapped           = it->second;
2600e6b6b59SJacob Faibussowitsch       //const auto         mode             = PetscMemoryAccessModes(mapped.mode);
2610e6b6b59SJacob Faibussowitsch 
2620e6b6b59SJacob Faibussowitsch       // for (auto &&dep : mapped.dependencies) {
2630e6b6b59SJacob Faibussowitsch       //   // if (!dep.ctx->options.allow_orphans) {
2640e6b6b59SJacob Faibussowitsch       //   //   wrote_to_oss_tmp = true;
2650e6b6b59SJacob Faibussowitsch       //   //   oss_tmp<<"  ["<<rank<<"] dctx "<<dep.ctx<<" (id "<<dep.dctx_id()<<", state "<<dep.dctx_state<<", intent "<<mode<<' '<<dep.frame()<<")\n";
2660e6b6b59SJacob Faibussowitsch       //   // }
2670e6b6b59SJacob Faibussowitsch       // }
2680e6b6b59SJacob Faibussowitsch       // check if we wrote to it
2690e6b6b59SJacob Faibussowitsch       if (wrote_to_oss_tmp) {
2700e6b6b59SJacob Faibussowitsch         oss << '[' << rank << "] object " << it->first << " has orphaned dependencies:\n" << oss_tmp.str();
2710e6b6b59SJacob Faibussowitsch         wrote_to_oss = true;
2720e6b6b59SJacob Faibussowitsch       }
2730e6b6b59SJacob Faibussowitsch     }
2740e6b6b59SJacob Faibussowitsch     if (wrote_to_oss) {
2750e6b6b59SJacob Faibussowitsch       //PetscCall((*PetscErrorPrintf)("%s\n",oss.str().c_str()));
2760e6b6b59SJacob Faibussowitsch       //SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Orphaned dependencies found, see above");
2770e6b6b59SJacob Faibussowitsch     }
2780e6b6b59SJacob Faibussowitsch   }
2790e6b6b59SJacob Faibussowitsch   // replace with new map, since clear() does not necessarily free memory
2800e6b6b59SJacob Faibussowitsch   PetscCallCXX(this->map = map_type{});
2810e6b6b59SJacob Faibussowitsch   PetscFunctionReturn(0);
2820e6b6b59SJacob Faibussowitsch }
2830e6b6b59SJacob Faibussowitsch 
2840e6b6b59SJacob Faibussowitsch // ==========================================================================================
2850e6b6b59SJacob Faibussowitsch // MarkedObejctMap::snapshot_type Private API
2860e6b6b59SJacob Faibussowitsch // ==========================================================================================
2870e6b6b59SJacob Faibussowitsch 
288*d71ae5a4SJacob Faibussowitsch inline PetscEvent MarkedObjectMap::snapshot_type::init_event_(PetscDeviceContext dctx) noexcept
289*d71ae5a4SJacob Faibussowitsch {
2900e6b6b59SJacob Faibussowitsch   PetscEvent event = nullptr;
2910e6b6b59SJacob Faibussowitsch 
2920e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
2930e6b6b59SJacob Faibussowitsch   PetscCallAbort(PETSC_COMM_SELF, PetscDeviceContextCreateEvent_Private(dctx, &event));
2940e6b6b59SJacob Faibussowitsch   PetscCallAbort(PETSC_COMM_SELF, PetscDeviceContextRecordEvent_Private(dctx, event));
2950e6b6b59SJacob Faibussowitsch   PetscFunctionReturn(event);
2960e6b6b59SJacob Faibussowitsch }
2970e6b6b59SJacob Faibussowitsch 
2980e6b6b59SJacob Faibussowitsch // ==========================================================================================
2990e6b6b59SJacob Faibussowitsch // MarkedObejctMap::snapshot_type Public API
3000e6b6b59SJacob Faibussowitsch // ==========================================================================================
3010e6b6b59SJacob Faibussowitsch 
3020e6b6b59SJacob Faibussowitsch MarkedObjectMap::snapshot_type::snapshot_type(PetscDeviceContext dctx, frame_type frame) noexcept : frame_type(std::move(frame)), event_(init_event_(dctx)) { }
3030e6b6b59SJacob Faibussowitsch 
304*d71ae5a4SJacob Faibussowitsch MarkedObjectMap::snapshot_type::~snapshot_type() noexcept
305*d71ae5a4SJacob Faibussowitsch {
3060e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
3070e6b6b59SJacob Faibussowitsch   PetscCallAbort(PETSC_COMM_SELF, PetscEventDestroy_Private(&event_));
3080e6b6b59SJacob Faibussowitsch   PetscFunctionReturnVoid();
3090e6b6b59SJacob Faibussowitsch }
3100e6b6b59SJacob Faibussowitsch 
3110e6b6b59SJacob Faibussowitsch // movable
3120e6b6b59SJacob Faibussowitsch MarkedObjectMap::snapshot_type::snapshot_type(snapshot_type &&other) noexcept : frame_type(std::move(other)), event_(Petsc::util::exchange(other.event_, nullptr)) { }
3130e6b6b59SJacob Faibussowitsch 
314*d71ae5a4SJacob Faibussowitsch MarkedObjectMap::snapshot_type &MarkedObjectMap::snapshot_type::operator=(snapshot_type &&other) noexcept
315*d71ae5a4SJacob Faibussowitsch {
3160e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
3170e6b6b59SJacob Faibussowitsch   if (this != &other) {
3180e6b6b59SJacob Faibussowitsch     frame_type::operator=(std::move(other));
3190e6b6b59SJacob Faibussowitsch     PetscCallAbort(PETSC_COMM_SELF, PetscEventDestroy_Private(&event_));
3200e6b6b59SJacob Faibussowitsch     event_ = Petsc::util::exchange(other.event_, nullptr);
3210e6b6b59SJacob Faibussowitsch   }
3220e6b6b59SJacob Faibussowitsch   PetscFunctionReturn(*this);
3230e6b6b59SJacob Faibussowitsch }
3240e6b6b59SJacob Faibussowitsch 
3250e6b6b59SJacob Faibussowitsch // A mapping between PetscObjectId (i.e. some PetscObject) to the list of PetscEvent's encoding
3260e6b6b59SJacob Faibussowitsch // the last time the PetscObject was accessed
3270e6b6b59SJacob Faibussowitsch static MarkedObjectMap marked_object_map;
3280e6b6b59SJacob Faibussowitsch 
3290e6b6b59SJacob Faibussowitsch // ==========================================================================================
3300e6b6b59SJacob Faibussowitsch // Utility Functions
3310e6b6b59SJacob Faibussowitsch // ==========================================================================================
3320e6b6b59SJacob Faibussowitsch 
3330e6b6b59SJacob Faibussowitsch template <typename T>
334*d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDeviceContextMapIterVisitor(PetscDeviceContext dctx, T &&callback) noexcept
335*d71ae5a4SJacob Faibussowitsch {
3360e6b6b59SJacob Faibussowitsch   const auto dctx_id    = PetscObjectCast(dctx)->id;
3370e6b6b59SJacob Faibussowitsch   auto      &dctx_deps  = CxxDataCast(dctx)->deps;
3380e6b6b59SJacob Faibussowitsch   auto      &object_map = marked_object_map.map;
3390e6b6b59SJacob Faibussowitsch 
3400e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
3410e6b6b59SJacob Faibussowitsch   for (auto &&dep : dctx_deps) {
3420e6b6b59SJacob Faibussowitsch     const auto mapit = object_map.find(dep);
3430e6b6b59SJacob Faibussowitsch 
3440e6b6b59SJacob Faibussowitsch     // Need this check since the final PetscDeviceContext may run through this *after* the map
3450e6b6b59SJacob Faibussowitsch     // has been finalized (and cleared), and hence might fail to find its dependencies. This is
3460e6b6b59SJacob Faibussowitsch     // perfectly valid since the user no longer cares about dangling dependencies after PETSc
3470e6b6b59SJacob Faibussowitsch     // is finalized
3480e6b6b59SJacob Faibussowitsch     if (PetscLikely(mapit != object_map.end())) {
3490e6b6b59SJacob Faibussowitsch       auto      &deps = mapit->second.dependencies;
3500e6b6b59SJacob Faibussowitsch       const auto end  = deps.end();
3510e6b6b59SJacob Faibussowitsch       const auto it   = std::remove_if(deps.begin(), end, [&](const MarkedObjectMap::snapshot_type &obj) { return obj.dctx_id() == dctx_id; });
3520e6b6b59SJacob Faibussowitsch 
3530e6b6b59SJacob Faibussowitsch       PetscCall(callback(mapit, deps.cbegin(), static_cast<decltype(deps.cend())>(it)));
3540e6b6b59SJacob Faibussowitsch       // remove ourselves
3550e6b6b59SJacob Faibussowitsch       PetscCallCXX(deps.erase(it, end));
3560e6b6b59SJacob Faibussowitsch       // continue to next object, but erase this one if it has no more dependencies
3570e6b6b59SJacob Faibussowitsch       if (deps.empty()) PetscCallCXX(object_map.erase(mapit));
3580e6b6b59SJacob Faibussowitsch     }
3590e6b6b59SJacob Faibussowitsch   }
3600e6b6b59SJacob Faibussowitsch   PetscCallCXX(dctx_deps.clear());
3610e6b6b59SJacob Faibussowitsch   PetscFunctionReturn(0);
3620e6b6b59SJacob Faibussowitsch }
3630e6b6b59SJacob Faibussowitsch 
364*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextSyncClearMap_Internal(PetscDeviceContext dctx)
365*d71ae5a4SJacob Faibussowitsch {
3660e6b6b59SJacob Faibussowitsch   using map_iterator = MarkedObjectMap::map_type::const_iterator;
3670e6b6b59SJacob Faibussowitsch   using dep_iterator = MarkedObjectMap::mapped_type::dependency_type::const_iterator;
3680e6b6b59SJacob Faibussowitsch 
3690e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
3700e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextMapIterVisitor(dctx, [&](map_iterator mapit, dep_iterator it, dep_iterator end) {
3710e6b6b59SJacob Faibussowitsch     PetscFunctionBegin;
3720e6b6b59SJacob Faibussowitsch     if (PetscDefined(USE_DEBUG_AND_INFO)) {
3730e6b6b59SJacob Faibussowitsch       std::ostringstream oss;
3740e6b6b59SJacob Faibussowitsch       const auto         mode = PetscMemoryAccessModeToString(mapit->second.mode);
3750e6b6b59SJacob Faibussowitsch 
3760e6b6b59SJacob Faibussowitsch       oss << "synced dctx " << PetscObjectCast(dctx)->id << ", remaining leaves for obj " << mapit->first << ": {";
3770e6b6b59SJacob Faibussowitsch       while (it != end) {
3780e6b6b59SJacob Faibussowitsch         oss << "[dctx " << it->dctx_id() << ", " << mode << ' ' << it->frame() << ']';
3790e6b6b59SJacob Faibussowitsch         if (++it != end) oss << ", ";
3800e6b6b59SJacob Faibussowitsch       }
3810e6b6b59SJacob Faibussowitsch       oss << '}';
3820e6b6b59SJacob Faibussowitsch       PetscCall(PetscInfo(nullptr, "%s\n", oss.str().c_str()));
3830e6b6b59SJacob Faibussowitsch     }
3840e6b6b59SJacob Faibussowitsch     PetscFunctionReturn(0);
3850e6b6b59SJacob Faibussowitsch   }));
3860e6b6b59SJacob Faibussowitsch   {
3870e6b6b59SJacob Faibussowitsch     // the recursive sync clear map call is unbounded in case of a dependenct loop so we make a
3880e6b6b59SJacob Faibussowitsch     // copy
3890e6b6b59SJacob Faibussowitsch     // clang-format off
3900e6b6b59SJacob Faibussowitsch     const std::vector<CxxData::upstream_type::value_type> upstream_copy(
3910e6b6b59SJacob Faibussowitsch       std::make_move_iterator(CxxDataCast(dctx)->upstream.begin()),
3920e6b6b59SJacob Faibussowitsch       std::make_move_iterator(CxxDataCast(dctx)->upstream.end())
3930e6b6b59SJacob Faibussowitsch     );
3940e6b6b59SJacob Faibussowitsch     // clang-format on
3950e6b6b59SJacob Faibussowitsch 
3960e6b6b59SJacob Faibussowitsch     // aftermath, clear our set of parents (to avoid infinite recursion) and mark ourselves as no
3970e6b6b59SJacob Faibussowitsch     // longer contained (while the empty graph technically *is* always contained, it is not what
3980e6b6b59SJacob Faibussowitsch     // we mean by it)
3990e6b6b59SJacob Faibussowitsch     PetscCall(CxxDataCast(dctx)->clear());
4000e6b6b59SJacob Faibussowitsch     //dctx->contained = PETSC_FALSE;
4010e6b6b59SJacob Faibussowitsch     for (auto &&upstrm : upstream_copy) {
4020e6b6b59SJacob Faibussowitsch       // check that this parent still points to what we originally thought it was
4030e6b6b59SJacob 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);
4040e6b6b59SJacob Faibussowitsch       PetscCall(PetscDeviceContextSyncClearMap_Internal(upstrm.first));
4050e6b6b59SJacob Faibussowitsch     }
4060e6b6b59SJacob Faibussowitsch   }
4070e6b6b59SJacob Faibussowitsch   PetscFunctionReturn(0);
4080e6b6b59SJacob Faibussowitsch }
4090e6b6b59SJacob Faibussowitsch 
410*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextCheckNotOrphaned_Internal(PetscDeviceContext dctx)
411*d71ae5a4SJacob Faibussowitsch {
4120e6b6b59SJacob Faibussowitsch   std::ostringstream oss;
4130e6b6b59SJacob Faibussowitsch   //const auto         allow = dctx->options.allow_orphans, contained = dctx->contained;
4140e6b6b59SJacob Faibussowitsch   const auto allow = true, contained = true;
4150e6b6b59SJacob Faibussowitsch   auto       wrote_to_oss = false;
4160e6b6b59SJacob Faibussowitsch   using map_iterator      = MarkedObjectMap::map_type::const_iterator;
4170e6b6b59SJacob Faibussowitsch   using dep_iterator      = MarkedObjectMap::mapped_type::dependency_type::const_iterator;
4180e6b6b59SJacob Faibussowitsch 
4190e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
4200e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextMapIterVisitor(dctx, [&](map_iterator mapit, dep_iterator it, dep_iterator end) {
4210e6b6b59SJacob Faibussowitsch     PetscFunctionBegin;
4220e6b6b59SJacob Faibussowitsch     if (allow || contained) PetscFunctionReturn(0);
4230e6b6b59SJacob Faibussowitsch     wrote_to_oss = true;
4240e6b6b59SJacob Faibussowitsch     oss << "- PetscObject (id " << mapit->first << "), intent " << PetscMemoryAccessModeToString(mapit->second.mode) << ' ' << it->frame();
4250e6b6b59SJacob Faibussowitsch     if (std::distance(it, end) == 0) oss << " (orphaned)"; // we were the only dependency
4260e6b6b59SJacob Faibussowitsch     oss << '\n';
4270e6b6b59SJacob Faibussowitsch     PetscFunctionReturn(0);
4280e6b6b59SJacob Faibussowitsch   }));
4290e6b6b59SJacob 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",
4300e6b6b59SJacob Faibussowitsch              PetscObjectCast(dctx)->name ? PetscObjectCast(dctx)->name : "unnamed", PetscObjectCast(dctx)->id, oss.str().c_str());
4310e6b6b59SJacob Faibussowitsch   PetscCall(CxxDataCast(dctx)->clear());
4320e6b6b59SJacob Faibussowitsch   PetscFunctionReturn(0);
4330e6b6b59SJacob Faibussowitsch }
4340e6b6b59SJacob Faibussowitsch 
4350e6b6b59SJacob Faibussowitsch template <bool use_debug>
436*d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDeviceContextMarkIntentFromID_Private(PetscDeviceContext dctx, PetscObjectId id, PetscMemoryAccessMode mode, PetscStackFrame<use_debug> frame, const char *name)
437*d71ae5a4SJacob Faibussowitsch {
4380e6b6b59SJacob Faibussowitsch #define DEBUG_INFO(mess, ...) PetscDebugInfo(dctx, "dctx %" PetscInt64_FMT " (%s) - obj %" PetscInt64_FMT " (%s): " mess, dctx_id, PetscObjectCast(dctx)->name ? PetscObjectCast(dctx)->name : "unnamed", id, name, ##__VA_ARGS__)
4390e6b6b59SJacob Faibussowitsch   const auto dctx_id             = PetscObjectCast(dctx)->id;
4400e6b6b59SJacob Faibussowitsch   auto      &marked              = marked_object_map.map[id];
4410e6b6b59SJacob Faibussowitsch   auto      &old_mode            = marked.mode;
4420e6b6b59SJacob Faibussowitsch   auto      &object_dependencies = marked.dependencies;
4430e6b6b59SJacob Faibussowitsch 
4440e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
4450e6b6b59SJacob Faibussowitsch   if ((mode == PETSC_MEMORY_ACCESS_READ) && (old_mode == mode)) {
4460e6b6b59SJacob Faibussowitsch     const auto end = object_dependencies.end();
4470e6b6b59SJacob Faibussowitsch     const auto it  = std::find_if(object_dependencies.begin(), end, [&](const MarkedObjectMap::snapshot_type &obj) { return obj.dctx_id() == dctx_id; });
4480e6b6b59SJacob Faibussowitsch 
4490e6b6b59SJacob Faibussowitsch     PetscCall(DEBUG_INFO("new mode (%s) COMPATIBLE with %s mode (%s), no need to serialize\n", PetscMemoryAccessModeToString(mode), PetscMemoryAccessModeToString(old_mode), object_dependencies.empty() ? "default" : "old"));
4500e6b6b59SJacob Faibussowitsch     if (it != end) {
4510e6b6b59SJacob Faibussowitsch       // we have been here before, all we must do is update our entry then we can bail
4520e6b6b59SJacob Faibussowitsch       PetscCall(DEBUG_INFO("found old self as dependency, updating\n"));
4530e6b6b59SJacob 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);
4540e6b6b59SJacob Faibussowitsch 
4550e6b6b59SJacob Faibussowitsch       it->frame() = std::move(frame);
4560e6b6b59SJacob Faibussowitsch       PetscCall(PetscDeviceContextRecordEvent_Private(dctx, it->event()));
4570e6b6b59SJacob Faibussowitsch       PetscFunctionReturn(0);
4580e6b6b59SJacob Faibussowitsch     }
4590e6b6b59SJacob Faibussowitsch 
4600e6b6b59SJacob Faibussowitsch     // we have not been here before, need to serialize with the last write event (if it exists)
4610e6b6b59SJacob Faibussowitsch     // and add ourselves to the dependency list
4620e6b6b59SJacob Faibussowitsch     if (const auto event = marked.last_write.event()) PetscCall(PetscDeviceContextWaitForEvent_Private(dctx, event));
4630e6b6b59SJacob Faibussowitsch   } else {
4640e6b6b59SJacob Faibussowitsch     // we are incompatible with the previous mode
4650e6b6b59SJacob 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),
4660e6b6b59SJacob Faibussowitsch                          object_dependencies.size(), object_dependencies.size() == 1 ? "dependency" : "dependencies"));
4670e6b6b59SJacob Faibussowitsch     for (const auto &dep : object_dependencies) {
4680e6b6b59SJacob Faibussowitsch       if (dep.dctx_id() == dctx_id) {
4690e6b6b59SJacob Faibussowitsch         PetscCall(DEBUG_INFO("found old self as dependency, skipping\n"));
4700e6b6b59SJacob Faibussowitsch         continue;
4710e6b6b59SJacob Faibussowitsch       }
4720e6b6b59SJacob Faibussowitsch       PetscCall(PetscDeviceContextWaitForEvent_Private(dctx, dep.event()));
4730e6b6b59SJacob Faibussowitsch     }
4740e6b6b59SJacob Faibussowitsch 
4750e6b6b59SJacob Faibussowitsch     // if the previous mode wrote, bump it to the previous write spot
4760e6b6b59SJacob Faibussowitsch     if (PetscMemoryAccessWrite(old_mode)) {
4770e6b6b59SJacob Faibussowitsch       PetscAssert(object_dependencies.size() == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Can only have a single writer as dependency!");
4780e6b6b59SJacob Faibussowitsch       PetscCall(DEBUG_INFO("moving last write dependency (intent %s)\n", PetscMemoryAccessModeToString(old_mode)));
4790e6b6b59SJacob Faibussowitsch       // note the move around object_dependencies.back() not around event(), this is to enable
4800e6b6b59SJacob Faibussowitsch       // the rvalue event() overload
4810e6b6b59SJacob Faibussowitsch       marked.last_write = std::move(object_dependencies.back());
4820e6b6b59SJacob Faibussowitsch     }
4830e6b6b59SJacob Faibussowitsch 
4840e6b6b59SJacob Faibussowitsch     // clear out the old dependencies and update the mode, we are about to append ourselves
4850e6b6b59SJacob Faibussowitsch     object_dependencies.clear();
4860e6b6b59SJacob Faibussowitsch     old_mode = mode;
4870e6b6b59SJacob Faibussowitsch   }
4880e6b6b59SJacob Faibussowitsch   // become the new leaf by appending ourselves
4890e6b6b59SJacob 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)));
4900e6b6b59SJacob Faibussowitsch   PetscCallCXX(object_dependencies.emplace_back(dctx, std::move(frame)));
4910e6b6b59SJacob Faibussowitsch   PetscCallCXX(CxxDataCast(dctx)->deps.emplace(id));
4920e6b6b59SJacob Faibussowitsch   PetscFunctionReturn(0);
4930e6b6b59SJacob Faibussowitsch #undef DEBUG_INFO
4940e6b6b59SJacob Faibussowitsch }
4950e6b6b59SJacob Faibussowitsch 
4960e6b6b59SJacob Faibussowitsch /*@C
4970e6b6b59SJacob Faibussowitsch   PetscDeviceContextMarkIntentFromID - Indicate a `PetscDeviceContext`s access intent to the
4980e6b6b59SJacob Faibussowitsch   auto-dependency system
4990e6b6b59SJacob Faibussowitsch 
5000e6b6b59SJacob Faibussowitsch   Not Collective
5010e6b6b59SJacob Faibussowitsch 
5020e6b6b59SJacob Faibussowitsch   Input Parameters:
5030e6b6b59SJacob Faibussowitsch + dctx - The `PetscDeviceContext`
5040e6b6b59SJacob Faibussowitsch . id   - The `PetscObjectId` to mark
5050e6b6b59SJacob Faibussowitsch . mode - The desired access intent
5060e6b6b59SJacob Faibussowitsch - name - The object name (for debug purposes, ignored in optimized builds)
5070e6b6b59SJacob Faibussowitsch 
5080e6b6b59SJacob Faibussowitsch   Notes:
5090e6b6b59SJacob Faibussowitsch   This routine formally informs the dependency system that `dctx` will access the object
5100e6b6b59SJacob Faibussowitsch   represented by `id` with `mode` and adds `dctx` to `id`'s list of dependencies (termed
5110e6b6b59SJacob Faibussowitsch   "leaves").
5120e6b6b59SJacob Faibussowitsch 
5130e6b6b59SJacob Faibussowitsch   If the existing set of leaves have an incompatible `PetscMemoryAccessMode` to `mode`, `dctx`
5140e6b6b59SJacob Faibussowitsch   will be serialized against them.
5150e6b6b59SJacob Faibussowitsch 
5160e6b6b59SJacob Faibussowitsch   Level: intermediate
5170e6b6b59SJacob Faibussowitsch 
5180e6b6b59SJacob Faibussowitsch .seealso: `PetscDeviceContextWaitForContext()`, `PetscDeviceContextSynchronize()`,
5190e6b6b59SJacob Faibussowitsch `PetscObjectGetId()`, `PetscMemoryAccessMode`
5200e6b6b59SJacob Faibussowitsch @*/
521*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDeviceContextMarkIntentFromID(PetscDeviceContext dctx, PetscObjectId id, PetscMemoryAccessMode mode, const char name[])
522*d71ae5a4SJacob Faibussowitsch {
5230e6b6b59SJacob Faibussowitsch #if PetscDefined(USE_DEBUG)
5240e6b6b59SJacob Faibussowitsch   const auto index    = petscstack.currentsize > 2 ? petscstack.currentsize - 2 : 0;
5250e6b6b59SJacob Faibussowitsch   const auto file     = petscstack.file[index];
5260e6b6b59SJacob Faibussowitsch   const auto function = petscstack.function[index];
5270e6b6b59SJacob Faibussowitsch   const auto line     = petscstack.line[index];
5280e6b6b59SJacob Faibussowitsch #else
5290e6b6b59SJacob Faibussowitsch   constexpr const char *file     = nullptr;
5300e6b6b59SJacob Faibussowitsch   constexpr const char *function = nullptr;
5310e6b6b59SJacob Faibussowitsch   constexpr auto        line     = 0;
5320e6b6b59SJacob Faibussowitsch #endif
5330e6b6b59SJacob Faibussowitsch 
5340e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
5350e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextGetOptionalNullContext_Internal(&dctx));
5360e6b6b59SJacob Faibussowitsch   if (name) PetscValidCharPointer(name, 4);
5370e6b6b59SJacob Faibussowitsch   PetscCall(marked_object_map.register_finalize());
5386a4a1270SPierre Jolivet   PetscCall(PetscLogEventBegin(DCONTEXT_Mark, dctx, nullptr, nullptr, nullptr));
5390e6b6b59SJacob Faibussowitsch   PetscCall(PetscDeviceContextMarkIntentFromID_Private(dctx, id, mode, MarkedObjectMap::snapshot_type::frame_type{file, function, line}, name ? name : "unknown object"));
5406a4a1270SPierre Jolivet   PetscCall(PetscLogEventEnd(DCONTEXT_Mark, dctx, nullptr, nullptr, nullptr));
5410e6b6b59SJacob Faibussowitsch   PetscFunctionReturn(0);
5420e6b6b59SJacob Faibussowitsch }
543a966a306SPierre Jolivet 
544a966a306SPierre Jolivet #if defined(__clang__)
545a966a306SPierre Jolivet   #pragma clang diagnostic pop
546a966a306SPierre Jolivet #endif
547