xref: /petsc/src/sys/objects/device/interface/petscdevice_interface_internal.hpp (revision dcf958e2725ed5b45a9e2d55931865b30238645c)
10e6b6b59SJacob Faibussowitsch #ifndef PETSCDEVICE_INTERFACE_INTERNAL_HPP
20e6b6b59SJacob Faibussowitsch #define PETSCDEVICE_INTERFACE_INTERNAL_HPP
30e6b6b59SJacob Faibussowitsch 
40e6b6b59SJacob Faibussowitsch #include <petsc/private/deviceimpl.h>
50e6b6b59SJacob Faibussowitsch 
60e6b6b59SJacob Faibussowitsch #include <petsc/private/cpp/utility.hpp> // std::pair
7*dcf958e2SJacob Faibussowitsch #include <petsc/private/cpp/memory.hpp>  // std::weak_ptr, std::shared_ptr
80e6b6b59SJacob Faibussowitsch 
90e6b6b59SJacob Faibussowitsch #include <unordered_map>
10*dcf958e2SJacob Faibussowitsch #include <algorithm> // std::lower_bound
11*dcf958e2SJacob Faibussowitsch 
12*dcf958e2SJacob Faibussowitsch // clang's unordered_set implementaiton outperforms the flat vector implementation in all
13*dcf958e2SJacob Faibussowitsch // cases. GCC on the other hand only does so for n > 512, before which it is almost twice as
14*dcf958e2SJacob Faibussowitsch // slow! Even when it does surpass the vector, the speedup is tiny (1.2x). So we use
15*dcf958e2SJacob Faibussowitsch // unordered_set for clang and hand-rolled flat set for GCC...
16*dcf958e2SJacob Faibussowitsch //
17*dcf958e2SJacob Faibussowitsch // https://godbolt.org/z/bb7EWf3s5
18*dcf958e2SJacob Faibussowitsch //
19*dcf958e2SJacob Faibussowitsch // This choice is consequential, since adding/checking marks is done for every
20*dcf958e2SJacob Faibussowitsch // PetscDeviceContextMarkIntentFromID() call
21*dcf958e2SJacob Faibussowitsch #ifdef __clang__
220e6b6b59SJacob Faibussowitsch   #include <unordered_set>
23*dcf958e2SJacob Faibussowitsch   #define PETSC_USE_UNORDERED_SET_FOR_MARKED 1
24*dcf958e2SJacob Faibussowitsch #else
25*dcf958e2SJacob Faibussowitsch   #include <vector>
26*dcf958e2SJacob Faibussowitsch   #define PETSC_USE_UNORDERED_SET_FOR_MARKED 0
27*dcf958e2SJacob Faibussowitsch #endif
280e6b6b59SJacob Faibussowitsch 
290e6b6b59SJacob Faibussowitsch #if PetscDefined(USE_DEBUG) && PetscDefined(USE_INFO)
300e6b6b59SJacob Faibussowitsch   #define PETSC_USE_DEBUG_AND_INFO  1
310e6b6b59SJacob Faibussowitsch   #define PetscDebugInfo(dctx, ...) PetscInfo(dctx, __VA_ARGS__)
320e6b6b59SJacob Faibussowitsch #else
333ba16761SJacob Faibussowitsch   #define PetscDebugInfo(dctx, ...) PETSC_SUCCESS
340e6b6b59SJacob Faibussowitsch #endif
350e6b6b59SJacob Faibussowitsch 
360e6b6b59SJacob Faibussowitsch // this file contains functions needed to bridge the gap between dcontext.cxx and device.cxx
370e6b6b59SJacob Faibussowitsch // but are not useful enough to put in the impl header
380e6b6b59SJacob Faibussowitsch PETSC_INTERN PetscErrorCode PetscDeviceContextSetDefaultDeviceForType_Internal(PetscDeviceContext, PetscDeviceType);
390e6b6b59SJacob Faibussowitsch PETSC_INTERN PetscErrorCode PetscDeviceContextSetRootDeviceType_Internal(PetscDeviceType);
400e6b6b59SJacob Faibussowitsch PETSC_INTERN PetscErrorCode PetscDeviceContextSetRootStreamType_Internal(PetscStreamType);
410e6b6b59SJacob Faibussowitsch PETSC_INTERN PetscErrorCode PetscDeviceContextSyncClearMap_Internal(PetscDeviceContext);
420e6b6b59SJacob Faibussowitsch PETSC_INTERN PetscErrorCode PetscDeviceContextCheckNotOrphaned_Internal(PetscDeviceContext);
430e6b6b59SJacob Faibussowitsch 
44*dcf958e2SJacob Faibussowitsch struct _n_WeakContext {
45*dcf958e2SJacob Faibussowitsch public:
46*dcf958e2SJacob Faibussowitsch   using weak_ptr_type = std::weak_ptr<_p_PetscDeviceContext>;
47*dcf958e2SJacob Faibussowitsch 
48*dcf958e2SJacob Faibussowitsch   constexpr _n_WeakContext() noexcept = default;
49*dcf958e2SJacob Faibussowitsch 
50*dcf958e2SJacob Faibussowitsch   void swap(_n_WeakContext &other) noexcept
51d71ae5a4SJacob Faibussowitsch   {
52*dcf958e2SJacob Faibussowitsch     using std::swap;
530e6b6b59SJacob Faibussowitsch 
54*dcf958e2SJacob Faibussowitsch     weak_dctx_.swap(other.weak_dctx_);
55*dcf958e2SJacob Faibussowitsch     swap(state_, other.state_);
56*dcf958e2SJacob Faibussowitsch   }
570e6b6b59SJacob Faibussowitsch 
58*dcf958e2SJacob Faibussowitsch   friend void swap(_n_WeakContext &lhs, _n_WeakContext &rhs) noexcept { lhs.swap(rhs); }
590e6b6b59SJacob Faibussowitsch 
60*dcf958e2SJacob Faibussowitsch   PETSC_NODISCARD const weak_ptr_type &weak_dctx() const noexcept { return weak_dctx_; }
610e6b6b59SJacob Faibussowitsch 
62*dcf958e2SJacob Faibussowitsch   PETSC_NODISCARD PetscObjectState state() const noexcept { return state_; }
630e6b6b59SJacob Faibussowitsch 
64*dcf958e2SJacob Faibussowitsch   void set_state(PetscObjectState state) noexcept { state_ = state; }
650e6b6b59SJacob Faibussowitsch 
660e6b6b59SJacob Faibussowitsch private:
67*dcf958e2SJacob Faibussowitsch   weak_ptr_type    weak_dctx_{};
68*dcf958e2SJacob Faibussowitsch   PetscObjectState state_{};
69*dcf958e2SJacob Faibussowitsch 
70*dcf958e2SJacob Faibussowitsch   friend class CxxData;
71*dcf958e2SJacob Faibussowitsch 
72*dcf958e2SJacob Faibussowitsch   explicit _n_WeakContext(const std::shared_ptr<_p_PetscDeviceContext> &ptr) noexcept : weak_dctx_{ptr}, state_{PetscObjectCast(ptr.get())->state} { }
730e6b6b59SJacob Faibussowitsch };
740e6b6b59SJacob Faibussowitsch 
75*dcf958e2SJacob Faibussowitsch class CxxData {
76*dcf958e2SJacob Faibussowitsch public:
77*dcf958e2SJacob Faibussowitsch   struct NoOpDeleter {
78*dcf958e2SJacob Faibussowitsch     PETSC_CONSTEXPR_14 void operator()(const void *) const noexcept { }
79*dcf958e2SJacob Faibussowitsch   };
800e6b6b59SJacob Faibussowitsch 
81*dcf958e2SJacob Faibussowitsch   using upstream_type = std::unordered_map<PetscObjectId, _n_WeakContext>;
82*dcf958e2SJacob Faibussowitsch #if PETSC_USE_UNORDERED_SET_FOR_MARKED
83*dcf958e2SJacob Faibussowitsch   using marked_type = std::unordered_set<PetscObjectId>;
84*dcf958e2SJacob Faibussowitsch #else
85*dcf958e2SJacob Faibussowitsch   using marked_type = std::vector<PetscObjectId>;
86*dcf958e2SJacob Faibussowitsch #endif
87*dcf958e2SJacob Faibussowitsch   using shared_ptr_type = std::shared_ptr<_p_PetscDeviceContext>;
880e6b6b59SJacob Faibussowitsch 
89*dcf958e2SJacob Faibussowitsch   explicit CxxData(PetscDeviceContext dctx) noexcept : self_{dctx, NoOpDeleter{}} { }
900e6b6b59SJacob Faibussowitsch 
91*dcf958e2SJacob Faibussowitsch   PETSC_NODISCARD const upstream_type   &upstream() const noexcept { return upstream_; }
92*dcf958e2SJacob Faibussowitsch   PETSC_NODISCARD upstream_type         &upstream() noexcept { return upstream_; }
93*dcf958e2SJacob Faibussowitsch   PETSC_NODISCARD const marked_type     &marked_objects() const noexcept { return marked_objects_; }
94*dcf958e2SJacob Faibussowitsch   PETSC_NODISCARD marked_type           &marked_objects() noexcept { return marked_objects_; }
95*dcf958e2SJacob Faibussowitsch   PETSC_NODISCARD const shared_ptr_type &self() const noexcept { return self_; }
96*dcf958e2SJacob Faibussowitsch 
97*dcf958e2SJacob Faibussowitsch   PetscErrorCode                 reset_self(PetscDeviceContext) noexcept;
98089fb57cSJacob Faibussowitsch   PetscErrorCode                 clear() noexcept;
99*dcf958e2SJacob Faibussowitsch   PETSC_NODISCARD _n_WeakContext weak_snapshot() const noexcept;
100*dcf958e2SJacob Faibussowitsch   PetscErrorCode                 add_mark(PetscObjectId) noexcept;
101*dcf958e2SJacob Faibussowitsch   PETSC_NODISCARD bool           has_marked(PetscObjectId) const noexcept;
102*dcf958e2SJacob Faibussowitsch 
103*dcf958e2SJacob Faibussowitsch private:
104*dcf958e2SJacob Faibussowitsch #if !PETSC_USE_UNORDERED_SET_FOR_MARKED
105*dcf958e2SJacob Faibussowitsch   PETSC_NODISCARD std::pair<bool, typename marked_type::iterator> get_marked_(PetscObjectId id) noexcept
106*dcf958e2SJacob Faibussowitsch   {
107*dcf958e2SJacob Faibussowitsch     auto end = this->marked_objects().end();
108*dcf958e2SJacob Faibussowitsch     auto it  = std::lower_bound(this->marked_objects().begin(), end, id);
109*dcf958e2SJacob Faibussowitsch 
110*dcf958e2SJacob Faibussowitsch     return {it != end && *it == id, it};
111*dcf958e2SJacob Faibussowitsch   }
112*dcf958e2SJacob Faibussowitsch #endif
113*dcf958e2SJacob Faibussowitsch 
114*dcf958e2SJacob Faibussowitsch   upstream_type   upstream_{};
115*dcf958e2SJacob Faibussowitsch   marked_type     marked_objects_{};
116*dcf958e2SJacob Faibussowitsch   shared_ptr_type self_{};
1170e6b6b59SJacob Faibussowitsch };
1180e6b6b59SJacob Faibussowitsch 
119*dcf958e2SJacob Faibussowitsch inline PetscErrorCode CxxData::reset_self(PetscDeviceContext dctx) noexcept
120*dcf958e2SJacob Faibussowitsch {
121*dcf958e2SJacob Faibussowitsch   PetscFunctionBegin;
122*dcf958e2SJacob Faibussowitsch   if (dctx) {
123*dcf958e2SJacob Faibussowitsch     PetscCallCXX(self_.reset(dctx, NoOpDeleter{}));
124*dcf958e2SJacob Faibussowitsch   } else {
125*dcf958e2SJacob Faibussowitsch     PetscCallCXX(self_.reset());
126*dcf958e2SJacob Faibussowitsch   }
127*dcf958e2SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
128*dcf958e2SJacob Faibussowitsch }
129*dcf958e2SJacob Faibussowitsch 
130d71ae5a4SJacob Faibussowitsch inline PetscErrorCode CxxData::clear() noexcept
131d71ae5a4SJacob Faibussowitsch {
1320e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
133*dcf958e2SJacob Faibussowitsch   PetscCallCXX(this->upstream().clear());
134*dcf958e2SJacob Faibussowitsch   PetscCallCXX(this->marked_objects().clear());
1353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1360e6b6b59SJacob Faibussowitsch }
1370e6b6b59SJacob Faibussowitsch 
138*dcf958e2SJacob Faibussowitsch inline _n_WeakContext CxxData::weak_snapshot() const noexcept
139*dcf958e2SJacob Faibussowitsch {
140*dcf958e2SJacob Faibussowitsch   return _n_WeakContext{this->self()};
141*dcf958e2SJacob Faibussowitsch }
142*dcf958e2SJacob Faibussowitsch 
143*dcf958e2SJacob Faibussowitsch inline PetscErrorCode CxxData::add_mark(PetscObjectId id) noexcept
144*dcf958e2SJacob Faibussowitsch {
145*dcf958e2SJacob Faibussowitsch   PetscFunctionBegin;
146*dcf958e2SJacob Faibussowitsch #if PETSC_USE_UNORDERED_SET_FOR_MARKED
147*dcf958e2SJacob Faibussowitsch   PetscCallCXX(marked_objects_.emplace(id));
148*dcf958e2SJacob Faibussowitsch #else
149*dcf958e2SJacob Faibussowitsch   const auto pair   = get_marked_(id);
150*dcf958e2SJacob Faibussowitsch 
151*dcf958e2SJacob Faibussowitsch   if (!pair.first) PetscCallCXX(marked_objects_.insert(pair.second, id));
152*dcf958e2SJacob Faibussowitsch #endif
153*dcf958e2SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
154*dcf958e2SJacob Faibussowitsch }
155*dcf958e2SJacob Faibussowitsch 
156*dcf958e2SJacob Faibussowitsch inline bool CxxData::has_marked(PetscObjectId id) const noexcept
157*dcf958e2SJacob Faibussowitsch {
158*dcf958e2SJacob Faibussowitsch #if PETSC_USE_UNORDERED_SET_FOR_MARKED
159*dcf958e2SJacob Faibussowitsch   return marked_objects().find(id) != marked_objects().end();
160*dcf958e2SJacob Faibussowitsch #else
161*dcf958e2SJacob Faibussowitsch   return const_cast<CxxData *>(this)->get_marked_(id).first;
162*dcf958e2SJacob Faibussowitsch #endif
163*dcf958e2SJacob Faibussowitsch }
164*dcf958e2SJacob Faibussowitsch 
165*dcf958e2SJacob Faibussowitsch #undef PETSC_USE_UNORDERED_SET_FOR_MARKED
166*dcf958e2SJacob Faibussowitsch 
167*dcf958e2SJacob Faibussowitsch namespace
168*dcf958e2SJacob Faibussowitsch {
169*dcf958e2SJacob Faibussowitsch 
170*dcf958e2SJacob Faibussowitsch PETSC_NODISCARD inline constexpr CxxData *CxxDataCast(PetscDeviceContext dctx) noexcept
171d71ae5a4SJacob Faibussowitsch {
1720e6b6b59SJacob Faibussowitsch   return static_cast<CxxData *>(PetscObjectCast(dctx)->cpp);
1730e6b6b59SJacob Faibussowitsch }
1740e6b6b59SJacob Faibussowitsch 
1750e6b6b59SJacob Faibussowitsch /*
1760e6b6b59SJacob Faibussowitsch   needed because PetscInitialize() needs to also query these options to set the defaults. Since
1770e6b6b59SJacob Faibussowitsch   it does not yet have a PetscDeviceContext to call this with, the actual options queries are
1780e6b6b59SJacob Faibussowitsch   abstracted out, so you can call this without one.
1790e6b6b59SJacob Faibussowitsch */
180d71ae5a4SJacob Faibussowitsch inline PetscErrorCode PetscDeviceContextQueryOptions_Internal(PetscOptionItems *PetscOptionsObject, std::pair<PetscDeviceType, PetscBool> &deviceType, std::pair<PetscStreamType, PetscBool> &streamType)
181d71ae5a4SJacob Faibussowitsch {
1820e6b6b59SJacob Faibussowitsch   auto dtype = static_cast<PetscInt>(deviceType.first);
1830e6b6b59SJacob Faibussowitsch   auto stype = static_cast<PetscInt>(streamType.first);
1840e6b6b59SJacob Faibussowitsch 
1850e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
1860e6b6b59SJacob Faibussowitsch   /* set the device type first */
1870e6b6b59SJacob Faibussowitsch   PetscCall(PetscOptionsEList("-device_context_device_type", "Underlying PetscDevice", "PetscDeviceContextSetDevice", PetscDeviceTypes, PETSC_DEVICE_MAX, PetscDeviceTypes[dtype], &dtype, &deviceType.second));
1880e6b6b59SJacob Faibussowitsch   PetscCall(PetscOptionsEList("-device_context_stream_type", "PetscDeviceContext PetscStreamType", "PetscDeviceContextSetStreamType", PetscStreamTypes, PETSC_STREAM_MAX, PetscStreamTypes[stype], &stype, &streamType.second));
1890e6b6b59SJacob Faibussowitsch   deviceType.first = PetscDeviceTypeCast(dtype);
1900e6b6b59SJacob Faibussowitsch   streamType.first = PetscStreamTypeCast(stype);
1913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1920e6b6b59SJacob Faibussowitsch }
1930e6b6b59SJacob Faibussowitsch 
1940e6b6b59SJacob Faibussowitsch } // anonymous namespace
1950e6b6b59SJacob Faibussowitsch 
1960e6b6b59SJacob Faibussowitsch #endif // PETSCDEVICE_INTERFACE_INTERNAL_HPP
197