xref: /petsc/src/sys/objects/device/interface/petscdevice_interface_internal.hpp (revision 6d8694c4fbab79f9439f1ad13c0386ba7ee1ca4b)
1a4963045SJacob Faibussowitsch #pragma once
20e6b6b59SJacob Faibussowitsch 
30e6b6b59SJacob Faibussowitsch #include <petsc/private/deviceimpl.h>
40e6b6b59SJacob Faibussowitsch 
50e6b6b59SJacob Faibussowitsch #include <petsc/private/cpp/utility.hpp> // std::pair
6dcf958e2SJacob Faibussowitsch #include <petsc/private/cpp/memory.hpp>  // std::weak_ptr, std::shared_ptr
70e6b6b59SJacob Faibussowitsch 
80e6b6b59SJacob Faibussowitsch #include <unordered_map>
9dcf958e2SJacob Faibussowitsch #include <algorithm> // std::lower_bound
10dcf958e2SJacob Faibussowitsch 
11baca6076SPierre Jolivet // clang's unordered_set implementation outperforms the flat vector implementation in all
12dcf958e2SJacob Faibussowitsch // cases. GCC on the other hand only does so for n > 512, before which it is almost twice as
13dcf958e2SJacob Faibussowitsch // slow! Even when it does surpass the vector, the speedup is tiny (1.2x). So we use
14dcf958e2SJacob Faibussowitsch // unordered_set for clang and hand-rolled flat set for GCC...
15dcf958e2SJacob Faibussowitsch //
16dcf958e2SJacob Faibussowitsch // https://godbolt.org/z/bb7EWf3s5
17dcf958e2SJacob Faibussowitsch //
18dcf958e2SJacob Faibussowitsch // This choice is consequential, since adding/checking marks is done for every
19dcf958e2SJacob Faibussowitsch // PetscDeviceContextMarkIntentFromID() call
20dcf958e2SJacob Faibussowitsch #ifdef __clang__
210e6b6b59SJacob Faibussowitsch   #include <unordered_set>
22dcf958e2SJacob Faibussowitsch   #define PETSC_USE_UNORDERED_SET_FOR_MARKED 1
23dcf958e2SJacob Faibussowitsch #else
24dcf958e2SJacob Faibussowitsch   #include <vector>
25dcf958e2SJacob Faibussowitsch   #define PETSC_USE_UNORDERED_SET_FOR_MARKED 0
26dcf958e2SJacob Faibussowitsch #endif
270e6b6b59SJacob Faibussowitsch 
280e6b6b59SJacob Faibussowitsch #if PetscDefined(USE_DEBUG) && PetscDefined(USE_INFO)
290e6b6b59SJacob Faibussowitsch   #define PETSC_USE_DEBUG_AND_INFO  1
300e6b6b59SJacob Faibussowitsch   #define PetscDebugInfo(dctx, ...) PetscInfo(dctx, __VA_ARGS__)
310e6b6b59SJacob Faibussowitsch #else
323ba16761SJacob Faibussowitsch   #define PetscDebugInfo(dctx, ...) PETSC_SUCCESS
330e6b6b59SJacob Faibussowitsch #endif
340e6b6b59SJacob Faibussowitsch 
350e6b6b59SJacob Faibussowitsch // this file contains functions needed to bridge the gap between dcontext.cxx and device.cxx
360e6b6b59SJacob Faibussowitsch // but are not useful enough to put in the impl header
370e6b6b59SJacob Faibussowitsch PETSC_INTERN PetscErrorCode PetscDeviceContextSetDefaultDeviceForType_Internal(PetscDeviceContext, PetscDeviceType);
380e6b6b59SJacob Faibussowitsch PETSC_INTERN PetscErrorCode PetscDeviceContextSetRootDeviceType_Internal(PetscDeviceType);
390e6b6b59SJacob Faibussowitsch PETSC_INTERN PetscErrorCode PetscDeviceContextSetRootStreamType_Internal(PetscStreamType);
400e6b6b59SJacob Faibussowitsch PETSC_INTERN PetscErrorCode PetscDeviceContextSyncClearMap_Internal(PetscDeviceContext);
410e6b6b59SJacob Faibussowitsch PETSC_INTERN PetscErrorCode PetscDeviceContextCheckNotOrphaned_Internal(PetscDeviceContext);
420e6b6b59SJacob Faibussowitsch 
43dcf958e2SJacob Faibussowitsch struct _n_WeakContext {
44dcf958e2SJacob Faibussowitsch public:
45dcf958e2SJacob Faibussowitsch   using weak_ptr_type = std::weak_ptr<_p_PetscDeviceContext>;
46dcf958e2SJacob Faibussowitsch 
47dcf958e2SJacob Faibussowitsch   constexpr _n_WeakContext() noexcept = default;
48dcf958e2SJacob Faibussowitsch 
swap_n_WeakContext49dcf958e2SJacob Faibussowitsch   void swap(_n_WeakContext &other) noexcept
50d71ae5a4SJacob Faibussowitsch   {
51dcf958e2SJacob Faibussowitsch     using std::swap;
520e6b6b59SJacob Faibussowitsch 
53dcf958e2SJacob Faibussowitsch     weak_dctx_.swap(other.weak_dctx_);
54dcf958e2SJacob Faibussowitsch     swap(state_, other.state_);
55dcf958e2SJacob Faibussowitsch   }
560e6b6b59SJacob Faibussowitsch 
swap(_n_WeakContext & lhs,_n_WeakContext & rhs)57dcf958e2SJacob Faibussowitsch   friend void swap(_n_WeakContext &lhs, _n_WeakContext &rhs) noexcept { lhs.swap(rhs); }
580e6b6b59SJacob Faibussowitsch 
weak_dctx_n_WeakContext59dcf958e2SJacob Faibussowitsch   PETSC_NODISCARD const weak_ptr_type &weak_dctx() const noexcept { return weak_dctx_; }
600e6b6b59SJacob Faibussowitsch 
state_n_WeakContext61dcf958e2SJacob Faibussowitsch   PETSC_NODISCARD PetscObjectState state() const noexcept { return state_; }
620e6b6b59SJacob Faibussowitsch 
set_state_n_WeakContext63dcf958e2SJacob Faibussowitsch   void set_state(PetscObjectState state) noexcept { state_ = state; }
640e6b6b59SJacob Faibussowitsch 
650e6b6b59SJacob Faibussowitsch private:
66dcf958e2SJacob Faibussowitsch   weak_ptr_type    weak_dctx_{};
67dcf958e2SJacob Faibussowitsch   PetscObjectState state_{};
68dcf958e2SJacob Faibussowitsch 
69dcf958e2SJacob Faibussowitsch   friend class CxxData;
70dcf958e2SJacob Faibussowitsch 
_n_WeakContext_n_WeakContext71dcf958e2SJacob Faibussowitsch   explicit _n_WeakContext(const std::shared_ptr<_p_PetscDeviceContext> &ptr) noexcept : weak_dctx_{ptr}, state_{PetscObjectCast(ptr.get())->state} { }
720e6b6b59SJacob Faibussowitsch };
730e6b6b59SJacob Faibussowitsch 
74dcf958e2SJacob Faibussowitsch class CxxData {
75dcf958e2SJacob Faibussowitsch public:
76dcf958e2SJacob Faibussowitsch   struct NoOpDeleter {
operator ()CxxData::NoOpDeleter77dcf958e2SJacob Faibussowitsch     PETSC_CONSTEXPR_14 void operator()(const void *) const noexcept { }
78dcf958e2SJacob Faibussowitsch   };
790e6b6b59SJacob Faibussowitsch 
80dcf958e2SJacob Faibussowitsch   using upstream_type = std::unordered_map<PetscObjectId, _n_WeakContext>;
81dcf958e2SJacob Faibussowitsch #if PETSC_USE_UNORDERED_SET_FOR_MARKED
82dcf958e2SJacob Faibussowitsch   using marked_type = std::unordered_set<PetscObjectId>;
83dcf958e2SJacob Faibussowitsch #else
84dcf958e2SJacob Faibussowitsch   using marked_type = std::vector<PetscObjectId>;
85dcf958e2SJacob Faibussowitsch #endif
86dcf958e2SJacob Faibussowitsch   using shared_ptr_type = std::shared_ptr<_p_PetscDeviceContext>;
870e6b6b59SJacob Faibussowitsch 
CxxData(PetscDeviceContext dctx)88dcf958e2SJacob Faibussowitsch   explicit CxxData(PetscDeviceContext dctx) noexcept : self_{dctx, NoOpDeleter{}} { }
890e6b6b59SJacob Faibussowitsch 
upstream() const90dcf958e2SJacob Faibussowitsch   PETSC_NODISCARD const upstream_type   &upstream() const noexcept { return upstream_; }
upstream()91dcf958e2SJacob Faibussowitsch   PETSC_NODISCARD upstream_type         &upstream() noexcept { return upstream_; }
marked_objects() const92dcf958e2SJacob Faibussowitsch   PETSC_NODISCARD const marked_type     &marked_objects() const noexcept { return marked_objects_; }
marked_objects()93dcf958e2SJacob Faibussowitsch   PETSC_NODISCARD marked_type           &marked_objects() noexcept { return marked_objects_; }
self() const94dcf958e2SJacob Faibussowitsch   PETSC_NODISCARD const shared_ptr_type &self() const noexcept { return self_; }
95dcf958e2SJacob Faibussowitsch 
96dcf958e2SJacob Faibussowitsch   PetscErrorCode                 reset_self(PetscDeviceContext) noexcept;
97089fb57cSJacob Faibussowitsch   PetscErrorCode                 clear() noexcept;
98dcf958e2SJacob Faibussowitsch   PETSC_NODISCARD _n_WeakContext weak_snapshot() const noexcept;
99dcf958e2SJacob Faibussowitsch   PetscErrorCode                 add_mark(PetscObjectId) noexcept;
100dcf958e2SJacob Faibussowitsch   PETSC_NODISCARD bool           has_marked(PetscObjectId) const noexcept;
101dcf958e2SJacob Faibussowitsch 
102dcf958e2SJacob Faibussowitsch private:
103dcf958e2SJacob Faibussowitsch #if !PETSC_USE_UNORDERED_SET_FOR_MARKED
get_marked_(PetscObjectId id)104dcf958e2SJacob Faibussowitsch   PETSC_NODISCARD std::pair<bool, typename marked_type::iterator> get_marked_(PetscObjectId id) noexcept
105dcf958e2SJacob Faibussowitsch   {
106dcf958e2SJacob Faibussowitsch     auto end = this->marked_objects().end();
107dcf958e2SJacob Faibussowitsch     auto it  = std::lower_bound(this->marked_objects().begin(), end, id);
108dcf958e2SJacob Faibussowitsch 
109dcf958e2SJacob Faibussowitsch     return {it != end && *it == id, it};
110dcf958e2SJacob Faibussowitsch   }
111dcf958e2SJacob Faibussowitsch #endif
112dcf958e2SJacob Faibussowitsch 
113dcf958e2SJacob Faibussowitsch   upstream_type   upstream_{};
114dcf958e2SJacob Faibussowitsch   marked_type     marked_objects_{};
115dcf958e2SJacob Faibussowitsch   shared_ptr_type self_{};
1160e6b6b59SJacob Faibussowitsch };
1170e6b6b59SJacob Faibussowitsch 
reset_self(PetscDeviceContext dctx)118dcf958e2SJacob Faibussowitsch inline PetscErrorCode CxxData::reset_self(PetscDeviceContext dctx) noexcept
119dcf958e2SJacob Faibussowitsch {
120dcf958e2SJacob Faibussowitsch   PetscFunctionBegin;
121dcf958e2SJacob Faibussowitsch   if (dctx) {
122dcf958e2SJacob Faibussowitsch     PetscCallCXX(self_.reset(dctx, NoOpDeleter{}));
123dcf958e2SJacob Faibussowitsch   } else {
124dcf958e2SJacob Faibussowitsch     PetscCallCXX(self_.reset());
125dcf958e2SJacob Faibussowitsch   }
126dcf958e2SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
127dcf958e2SJacob Faibussowitsch }
128dcf958e2SJacob Faibussowitsch 
clear()129d71ae5a4SJacob Faibussowitsch inline PetscErrorCode CxxData::clear() noexcept
130d71ae5a4SJacob Faibussowitsch {
1310e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
132dcf958e2SJacob Faibussowitsch   PetscCallCXX(this->upstream().clear());
133dcf958e2SJacob Faibussowitsch   PetscCallCXX(this->marked_objects().clear());
1343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1350e6b6b59SJacob Faibussowitsch }
1360e6b6b59SJacob Faibussowitsch 
weak_snapshot() const137dcf958e2SJacob Faibussowitsch inline _n_WeakContext CxxData::weak_snapshot() const noexcept
138dcf958e2SJacob Faibussowitsch {
139dcf958e2SJacob Faibussowitsch   return _n_WeakContext{this->self()};
140dcf958e2SJacob Faibussowitsch }
141dcf958e2SJacob Faibussowitsch 
add_mark(PetscObjectId id)142dcf958e2SJacob Faibussowitsch inline PetscErrorCode CxxData::add_mark(PetscObjectId id) noexcept
143dcf958e2SJacob Faibussowitsch {
144dcf958e2SJacob Faibussowitsch   PetscFunctionBegin;
145dcf958e2SJacob Faibussowitsch #if PETSC_USE_UNORDERED_SET_FOR_MARKED
146dcf958e2SJacob Faibussowitsch   PetscCallCXX(marked_objects_.emplace(id));
147dcf958e2SJacob Faibussowitsch #else
148dcf958e2SJacob Faibussowitsch   const auto pair = get_marked_(id);
149dcf958e2SJacob Faibussowitsch 
150dcf958e2SJacob Faibussowitsch   if (!pair.first) PetscCallCXX(marked_objects_.insert(pair.second, id));
151dcf958e2SJacob Faibussowitsch #endif
152dcf958e2SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
153dcf958e2SJacob Faibussowitsch }
154dcf958e2SJacob Faibussowitsch 
has_marked(PetscObjectId id) const155dcf958e2SJacob Faibussowitsch inline bool CxxData::has_marked(PetscObjectId id) const noexcept
156dcf958e2SJacob Faibussowitsch {
157dcf958e2SJacob Faibussowitsch #if PETSC_USE_UNORDERED_SET_FOR_MARKED
158dcf958e2SJacob Faibussowitsch   return marked_objects().find(id) != marked_objects().end();
159dcf958e2SJacob Faibussowitsch #else
160dcf958e2SJacob Faibussowitsch   return const_cast<CxxData *>(this)->get_marked_(id).first;
161dcf958e2SJacob Faibussowitsch #endif
162dcf958e2SJacob Faibussowitsch }
163dcf958e2SJacob Faibussowitsch 
164dcf958e2SJacob Faibussowitsch #undef PETSC_USE_UNORDERED_SET_FOR_MARKED
165dcf958e2SJacob Faibussowitsch 
166dcf958e2SJacob Faibussowitsch namespace
167dcf958e2SJacob Faibussowitsch {
168dcf958e2SJacob Faibussowitsch 
CxxDataCast(PetscDeviceContext dctx)1694a6d6d14SPierre Jolivet PETSC_NODISCARD inline CxxData *CxxDataCast(PetscDeviceContext dctx) noexcept
170d71ae5a4SJacob Faibussowitsch {
1710e6b6b59SJacob Faibussowitsch   return static_cast<CxxData *>(PetscObjectCast(dctx)->cpp);
1720e6b6b59SJacob Faibussowitsch }
1730e6b6b59SJacob Faibussowitsch 
1740e6b6b59SJacob Faibussowitsch /*
1750e6b6b59SJacob Faibussowitsch   needed because PetscInitialize() needs to also query these options to set the defaults. Since
1760e6b6b59SJacob Faibussowitsch   it does not yet have a PetscDeviceContext to call this with, the actual options queries are
1770e6b6b59SJacob Faibussowitsch   abstracted out, so you can call this without one.
1780e6b6b59SJacob Faibussowitsch */
PetscDeviceContextQueryOptions_Internal(PetscOptionItems PetscOptionsObject,std::pair<PetscDeviceType,PetscBool> & deviceType,std::pair<PetscStreamType,PetscBool> & streamType)179*ce78bad3SBarry Smith inline PetscErrorCode PetscDeviceContextQueryOptions_Internal(PetscOptionItems PetscOptionsObject, std::pair<PetscDeviceType, PetscBool> &deviceType, std::pair<PetscStreamType, PetscBool> &streamType)
180d71ae5a4SJacob Faibussowitsch {
1810e6b6b59SJacob Faibussowitsch   auto dtype = static_cast<PetscInt>(deviceType.first);
1820e6b6b59SJacob Faibussowitsch   auto stype = static_cast<PetscInt>(streamType.first);
1830e6b6b59SJacob Faibussowitsch 
1840e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
1850e6b6b59SJacob Faibussowitsch   /* set the device type first */
1860e6b6b59SJacob Faibussowitsch   PetscCall(PetscOptionsEList("-device_context_device_type", "Underlying PetscDevice", "PetscDeviceContextSetDevice", PetscDeviceTypes, PETSC_DEVICE_MAX, PetscDeviceTypes[dtype], &dtype, &deviceType.second));
1870e6b6b59SJacob Faibussowitsch   PetscCall(PetscOptionsEList("-device_context_stream_type", "PetscDeviceContext PetscStreamType", "PetscDeviceContextSetStreamType", PetscStreamTypes, PETSC_STREAM_MAX, PetscStreamTypes[stype], &stype, &streamType.second));
1880e6b6b59SJacob Faibussowitsch   deviceType.first = PetscDeviceTypeCast(dtype);
1890e6b6b59SJacob Faibussowitsch   streamType.first = PetscStreamTypeCast(stype);
1903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1910e6b6b59SJacob Faibussowitsch }
1920e6b6b59SJacob Faibussowitsch 
1930e6b6b59SJacob Faibussowitsch } // anonymous namespace
194