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 11*baca6076SPierre 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 49dcf958e2SJacob 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 57dcf958e2SJacob Faibussowitsch friend void swap(_n_WeakContext &lhs, _n_WeakContext &rhs) noexcept { lhs.swap(rhs); } 580e6b6b59SJacob Faibussowitsch 59dcf958e2SJacob Faibussowitsch PETSC_NODISCARD const weak_ptr_type &weak_dctx() const noexcept { return weak_dctx_; } 600e6b6b59SJacob Faibussowitsch 61dcf958e2SJacob Faibussowitsch PETSC_NODISCARD PetscObjectState state() const noexcept { return state_; } 620e6b6b59SJacob Faibussowitsch 63dcf958e2SJacob 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 71dcf958e2SJacob 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 { 77dcf958e2SJacob 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 88dcf958e2SJacob Faibussowitsch explicit CxxData(PetscDeviceContext dctx) noexcept : self_{dctx, NoOpDeleter{}} { } 890e6b6b59SJacob Faibussowitsch 90dcf958e2SJacob Faibussowitsch PETSC_NODISCARD const upstream_type &upstream() const noexcept { return upstream_; } 91dcf958e2SJacob Faibussowitsch PETSC_NODISCARD upstream_type &upstream() noexcept { return upstream_; } 92dcf958e2SJacob Faibussowitsch PETSC_NODISCARD const marked_type &marked_objects() const noexcept { return marked_objects_; } 93dcf958e2SJacob Faibussowitsch PETSC_NODISCARD marked_type &marked_objects() noexcept { return marked_objects_; } 94dcf958e2SJacob 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 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 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 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 137dcf958e2SJacob Faibussowitsch inline _n_WeakContext CxxData::weak_snapshot() const noexcept 138dcf958e2SJacob Faibussowitsch { 139dcf958e2SJacob Faibussowitsch return _n_WeakContext{this->self()}; 140dcf958e2SJacob Faibussowitsch } 141dcf958e2SJacob Faibussowitsch 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 155dcf958e2SJacob 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 169dcf958e2SJacob Faibussowitsch PETSC_NODISCARD inline constexpr 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 */ 179d71ae5a4SJacob Faibussowitsch 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