xref: /petsc/src/sys/objects/device/interface/petscdevice_interface_internal.hpp (revision fbf9dbe564678ed6eff1806adbc4c4f01b9743f4)
1 #ifndef PETSCDEVICE_INTERFACE_INTERNAL_HPP
2 #define PETSCDEVICE_INTERFACE_INTERNAL_HPP
3 
4 #include <petsc/private/deviceimpl.h>
5 
6 #include <petsc/private/cpp/utility.hpp>    // std::pair
7 #include <petsc/private/cpp/functional.hpp> //std::equal_to
8 
9 #include <unordered_map>
10 #include <unordered_set>
11 
12 #if PetscDefined(USE_DEBUG) && PetscDefined(USE_INFO)
13   #define PETSC_USE_DEBUG_AND_INFO  1
14   #define PetscDebugInfo(dctx, ...) PetscInfo(dctx, __VA_ARGS__)
15 #else
16   #define PetscDebugInfo(dctx, ...) PETSC_SUCCESS
17 #endif
18 
19 // this file contains functions needed to bridge the gap between dcontext.cxx and device.cxx
20 // but are not useful enough to put in the impl header
21 PETSC_INTERN PetscErrorCode PetscDeviceContextSetDefaultDeviceForType_Internal(PetscDeviceContext, PetscDeviceType);
22 PETSC_INTERN PetscErrorCode PetscDeviceContextSetRootDeviceType_Internal(PetscDeviceType);
23 PETSC_INTERN PetscErrorCode PetscDeviceContextSetRootStreamType_Internal(PetscStreamType);
24 PETSC_INTERN PetscErrorCode PetscDeviceContextSyncClearMap_Internal(PetscDeviceContext);
25 PETSC_INTERN PetscErrorCode PetscDeviceContextCheckNotOrphaned_Internal(PetscDeviceContext);
26 
27 // open up namespace std to specialize equal_to for unordered_map
28 namespace std
29 {
30 
31 template <>
32 struct equal_to<PetscDeviceContext> {
33 #if PETSC_CPP_VERSION <= 17
34   using result_type          = bool;
35   using first_argument_type  = PetscDeviceContext;
36   using second_argument_type = PetscDeviceContext;
37 #endif
38 
39   constexpr bool operator()(const PetscDeviceContext &x, const PetscDeviceContext &y) const noexcept { return PetscObjectCast(x)->id == PetscObjectCast(y)->id; }
40 };
41 
42 } // namespace std
43 
44 namespace
45 {
46 
47 // workaround for bug in:
48 // clang: https://bugs.llvm.org/show_bug.cgi?id=36684
49 // gcc: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96645
50 //
51 // see also:
52 // https://stackoverflow.com/questions/53408962/try-to-understand-compiler-error-message-default-member-initializer-required-be
53 struct CxxDataParent {
54   PetscObjectId    id    = 0;
55   PetscObjectState state = 0;
56 
57   constexpr CxxDataParent() noexcept = default;
58 
59   constexpr explicit CxxDataParent(PetscDeviceContext dctx) noexcept : CxxDataParent(PetscObjectCast(dctx)->id, PetscObjectCast(dctx)->state) { }
60 
61 private:
62   // make this private, we do not want to accept any old id and state pairing
63   constexpr CxxDataParent(PetscObjectId id_, PetscObjectState state_) noexcept : id(id_), state(state_) { }
64 };
65 
66 struct CxxData {
67   using upstream_type = std::unordered_map<PetscDeviceContext, CxxDataParent>;
68   using dep_type      = std::unordered_set<PetscObjectId>;
69 
70   // double check we didn't specialize for no reason
71   static_assert(std::is_same<typename upstream_type::key_equal, std::equal_to<PetscDeviceContext>>::value, "");
72 
73   upstream_type upstream{};
74   dep_type      deps{};
75 
76   PetscErrorCode clear() noexcept;
77 };
78 
79 inline PetscErrorCode CxxData::clear() noexcept
80 {
81   PetscFunctionBegin;
82   PetscCallCXX(this->upstream.clear());
83   PetscCallCXX(this->deps.clear());
84   PetscFunctionReturn(PETSC_SUCCESS);
85 }
86 
87 PETSC_NODISCARD inline CxxData *CxxDataCast(PetscDeviceContext dctx) noexcept
88 {
89   return static_cast<CxxData *>(PetscObjectCast(dctx)->cpp);
90 }
91 
92 /*
93   needed because PetscInitialize() needs to also query these options to set the defaults. Since
94   it does not yet have a PetscDeviceContext to call this with, the actual options queries are
95   abstracted out, so you can call this without one.
96 */
97 inline PetscErrorCode PetscDeviceContextQueryOptions_Internal(PetscOptionItems *PetscOptionsObject, std::pair<PetscDeviceType, PetscBool> &deviceType, std::pair<PetscStreamType, PetscBool> &streamType)
98 {
99   auto dtype = static_cast<PetscInt>(deviceType.first);
100   auto stype = static_cast<PetscInt>(streamType.first);
101 
102   PetscFunctionBegin;
103   /* set the device type first */
104   PetscCall(PetscOptionsEList("-device_context_device_type", "Underlying PetscDevice", "PetscDeviceContextSetDevice", PetscDeviceTypes, PETSC_DEVICE_MAX, PetscDeviceTypes[dtype], &dtype, &deviceType.second));
105   PetscCall(PetscOptionsEList("-device_context_stream_type", "PetscDeviceContext PetscStreamType", "PetscDeviceContextSetStreamType", PetscStreamTypes, PETSC_STREAM_MAX, PetscStreamTypes[stype], &stype, &streamType.second));
106   deviceType.first = PetscDeviceTypeCast(dtype);
107   streamType.first = PetscStreamTypeCast(stype);
108   PetscFunctionReturn(PETSC_SUCCESS);
109 }
110 
111 } // anonymous namespace
112 
113 #endif // PETSCDEVICE_INTERFACE_INTERNAL_HPP
114