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