Actual source code: impldevicebase.hpp
1: #ifndef IMPLDEVICEBASE_HPP
2: #define IMPLDEVICEBASE_HPP
4: #if defined(__cplusplus)
5: #include <petsc/private/deviceimpl.h>
6: #include <petsc/private/viewerimpl.h>
8: #include <petsc/private/cpp/crtp.hpp>
9: #include <petsc/private/cpp/type_traits.hpp>
10: #include <petsc/private/cpp/utility.hpp>
11: #include <petsc/private/cpp/array.hpp>
13: #include <cstring> // for std::strlen
15: namespace Petsc
16: {
18: namespace device
19: {
21: namespace impl
22: {
24: template <typename Derived> // CRTP
25: class DeviceBase : public util::crtp<Derived, DeviceBase> {
26: public:
27: using derived_type = Derived;
28: using createContextFunction_t = PetscErrorCode (*)(PetscDeviceContext);
30: // default constructor
31: constexpr DeviceBase(createContextFunction_t f) noexcept : create_(f) { }
33: template <typename T = derived_type>
34: PETSC_NODISCARD static constexpr PetscDeviceType PETSC_DEVICE_IMPL() noexcept
35: {
36: return T::PETSC_DEVICE_IMPL_();
37: }
39: PETSC_NODISCARD PetscErrorCode getDevice(PetscDevice, PetscInt) noexcept;
40: PETSC_NODISCARD static PetscErrorCode configureDevice(PetscDevice) noexcept;
41: PETSC_NODISCARD static PetscErrorCode viewDevice(PetscDevice, PetscViewer) noexcept;
42: PETSC_NODISCARD static PetscErrorCode getAttribute(PetscDevice, PetscDeviceAttribute, void *) noexcept;
44: protected:
45: // function to create a PetscDeviceContext (the (*create) function pointer usually set
46: // via XXXSetType() for other PETSc objects)
47: const createContextFunction_t create_;
49: // if you want the base class to handle the entire options query, has the same arguments as
50: // PetscOptionDeviceBasic
51: PETSC_NODISCARD static PetscErrorCode PetscOptionDeviceAll(MPI_Comm, std::pair<PetscDeviceInitType, PetscBool> &, std::pair<PetscInt, PetscBool> &, std::pair<PetscBool, PetscBool> &) noexcept;
53: // if you want to start and end the options query yourself, but still want all the default
54: // options
55: PETSC_NODISCARD static PetscErrorCode PetscOptionDeviceBasic(PetscOptionItems *, std::pair<PetscDeviceInitType, PetscBool> &, std::pair<PetscInt, PetscBool> &, std::pair<PetscBool, PetscBool> &) noexcept;
57: // option templates to follow, each one has two forms:
58: // - A simple form returning only the value and flag. This gives no control over the message,
59: // arguments to the options query or otherwise
60: // - A complex form, which allows you to pass most of the options query arguments *EXCEPT*
61: // - The options query function called
62: // - The option string
64: // option template for initializing the device
65: PETSC_NODISCARD static PetscErrorCode PetscOptionDeviceInitialize(PetscOptionItems *, PetscDeviceInitType *, PetscBool *) noexcept;
66: template <typename... T, util::enable_if_t<sizeof...(T) >= 3, int> = 0>
67: PETSC_NODISCARD static PetscErrorCode PetscOptionDeviceInitialize(PetscOptionItems *, T &&...) noexcept;
68: // option template for selecting the default device
69: PETSC_NODISCARD static PetscErrorCode PetscOptionDeviceSelect(PetscOptionItems *, PetscInt *, PetscBool *) noexcept;
70: template <typename... T, util::enable_if_t<sizeof...(T) >= 3, int> = 0>
71: PETSC_NODISCARD static PetscErrorCode PetscOptionDeviceSelect(PetscOptionItems *, T &&...) noexcept;
72: // option templates for viewing a device
73: PETSC_NODISCARD static PetscErrorCode PetscOptionDeviceView(PetscOptionItems *, PetscBool *, PetscBool *) noexcept;
74: template <typename... T, util::enable_if_t<sizeof...(T) >= 3, int> = 0>
75: PETSC_NODISCARD static PetscErrorCode PetscOptionDeviceView(PetscOptionItems *, T &&...) noexcept;
77: private:
78: // base function for all options templates above, they basically just reformat the arguments,
79: // create the option string and pass it off to this function
80: template <typename... T, typename F = PetscErrorCode (*)(PetscOptionItems *, const char *, T &&...)>
81: PETSC_NODISCARD static PetscErrorCode PetscOptionDevice(F &&, PetscOptionItems *, const char[], T &&...) noexcept;
83: // default crtp implementations
84: PETSC_NODISCARD static PetscErrorCode init_device_id_(PetscInt *id) noexcept
85: {
86: *id = 0;
87: return 0;
88: }
90: PETSC_NODISCARD static constexpr PetscErrorCode configure_device_(PetscDevice) noexcept { return 0; }
91: PETSC_NODISCARD static constexpr PetscErrorCode view_device_(PetscDevice, PetscViewer) noexcept { return 0; }
92: };
94: template <typename D>
95: inline PetscErrorCode DeviceBase<D>::getDevice(PetscDevice device, PetscInt id) noexcept
96: {
97: this->underlying().init_device_id_(&id);
98: device->deviceId = id;
99: device->ops->createcontext = this->underlying().create_;
100: device->ops->configure = this->underlying().configureDevice;
101: device->ops->view = this->underlying().viewDevice;
102: device->ops->getattribute = this->underlying().getAttribute;
103: return 0;
104: }
106: template <typename D>
107: inline PetscErrorCode DeviceBase<D>::configureDevice(PetscDevice device) noexcept
108: {
109: derived_type::configure_device_(device);
110: return 0;
111: }
113: template <typename D>
114: inline PetscErrorCode DeviceBase<D>::viewDevice(PetscDevice device, PetscViewer viewer) noexcept
115: {
116: derived_type::view_device_(device, viewer);
117: return 0;
118: }
120: template <typename D>
121: inline PetscErrorCode DeviceBase<D>::getAttribute(PetscDevice device, PetscDeviceAttribute attr, void *value) noexcept
122: {
123: derived_type::get_attribute_(device->deviceId, attr, value);
124: return 0;
125: }
127: template <typename D>
128: template <typename... T, typename F>
129: inline PetscErrorCode DeviceBase<D>::PetscOptionDevice(F &&OptionsFunction, PetscOptionItems *PetscOptionsObject, const char optstub[], T &&...args) noexcept
130: {
131: constexpr auto dtype = PETSC_DEVICE_IMPL();
132: const auto implname = PetscDeviceTypes[dtype];
133: auto buf = std::array<char, 128>{};
134: constexpr auto buflen = buf.size() - 1;
136: if (PetscDefined(USE_DEBUG)) {
137: const auto len = std::strlen(optstub) + std::strlen(implname);
140: }
141: PetscSNPrintf(buf.data(), buflen, "%s%s", optstub, implname);
142: OptionsFunction(PetscOptionsObject, buf.data(), std::forward<T>(args)...);
143: return 0;
144: }
146: template <typename D>
147: template <typename... T, util::enable_if_t<sizeof...(T) >= 3, int>>
148: inline PetscErrorCode DeviceBase<D>::PetscOptionDeviceInitialize(PetscOptionItems *PetscOptionsObject, T &&...args) noexcept
149: {
150: PetscOptionDevice(PetscOptionsEList_Private, PetscOptionsObject, "-device_enable_", std::forward<T>(args)...);
151: return 0;
152: }
154: template <typename D>
155: inline PetscErrorCode DeviceBase<D>::PetscOptionDeviceInitialize(PetscOptionItems *PetscOptionsObject, PetscDeviceInitType *inittype, PetscBool *flag) noexcept
156: {
157: auto type = static_cast<PetscInt>(util::integral_value(*inittype));
159: PetscOptionDeviceInitialize(PetscOptionsObject, "How (or whether) to initialize a device", "PetscDeviceInitialize()", PetscDeviceInitTypes, 3, PetscDeviceInitTypes[type], &type, flag);
160: *inittype = static_cast<PetscDeviceInitType>(type);
161: return 0;
162: }
164: template <typename D>
165: template <typename... T, util::enable_if_t<sizeof...(T) >= 3, int>>
166: inline PetscErrorCode DeviceBase<D>::PetscOptionDeviceSelect(PetscOptionItems *PetscOptionsObject, T &&...args) noexcept
167: {
168: PetscOptionDevice(PetscOptionsInt_Private, PetscOptionsObject, "-device_select_", std::forward<T>(args)...);
169: return 0;
170: }
172: template <typename D>
173: inline PetscErrorCode DeviceBase<D>::PetscOptionDeviceSelect(PetscOptionItems *PetscOptionsObject, PetscInt *id, PetscBool *flag) noexcept
174: {
175: PetscOptionDeviceSelect(PetscOptionsObject, "Which device to use. Pass " PetscStringize(PETSC_DECIDE) " to have PETSc decide or (given they exist) [0-" PetscStringize(PETSC_DEVICE_MAX_DEVICES) ") for a specific device", "PetscDeviceCreate()", *id, id, flag, PETSC_DECIDE, PETSC_DEVICE_MAX_DEVICES);
176: return 0;
177: }
179: template <typename D>
180: template <typename... T, util::enable_if_t<sizeof...(T) >= 3, int>>
181: inline PetscErrorCode DeviceBase<D>::PetscOptionDeviceView(PetscOptionItems *PetscOptionsObject, T &&...args) noexcept
182: {
183: PetscOptionDevice(PetscOptionsBool_Private, PetscOptionsObject, "-device_view_", std::forward<T>(args)...);
184: return 0;
185: }
187: template <typename D>
188: inline PetscErrorCode DeviceBase<D>::PetscOptionDeviceView(PetscOptionItems *PetscOptionsObject, PetscBool *view, PetscBool *flag) noexcept
189: {
190: PetscOptionDeviceView(PetscOptionsObject, "Display device information and assignments (forces eager initialization)", "PetscDeviceView()", *view, view, flag);
191: return 0;
192: }
194: template <typename D>
195: inline PetscErrorCode DeviceBase<D>::PetscOptionDeviceBasic(PetscOptionItems *PetscOptionsObject, std::pair<PetscDeviceInitType, PetscBool> &initType, std::pair<PetscInt, PetscBool> &initId, std::pair<PetscBool, PetscBool> &initView) noexcept
196: {
197: PetscOptionDeviceInitialize(PetscOptionsObject, &initType.first, &initType.second);
198: PetscOptionDeviceSelect(PetscOptionsObject, &initId.first, &initId.second);
199: PetscOptionDeviceView(PetscOptionsObject, &initView.first, &initView.second);
200: return 0;
201: }
203: template <typename D>
204: inline PetscErrorCode DeviceBase<D>::PetscOptionDeviceAll(MPI_Comm comm, std::pair<PetscDeviceInitType, PetscBool> &initType, std::pair<PetscInt, PetscBool> &initId, std::pair<PetscBool, PetscBool> &initView) noexcept
205: {
206: constexpr char optname[] = "PetscDevice %s Options";
207: constexpr auto dtype = PETSC_DEVICE_IMPL();
208: const auto implname = PetscDeviceTypes[dtype];
209: auto buf = std::array<char, 128>{};
210: constexpr auto buflen = buf.size() - 1; // -1 to leave room for null
212: if (PetscDefined(USE_DEBUG)) {
213: // -3 since '%s' is replaced and dont count null char for optname
214: const auto len = std::strlen(implname) + PETSC_STATIC_ARRAY_LENGTH(optname) - 3;
217: }
218: PetscSNPrintf(buf.data(), buflen, optname, implname);
219: PetscOptionsBegin(comm, nullptr, buf.data(), "Sys");
220: PetscOptionDeviceBasic(PetscOptionsObject, initType, initId, initView);
221: PetscOptionsEnd();
222: return 0;
223: }
225: } // namespace impl
227: } // namespace device
229: } // namespace Petsc
231: #define PETSC_DEVICE_IMPL_BASE_CLASS_HEADER(base_name, T) \
232: using base_name = ::Petsc::device::impl::DeviceBase<T>; \
233: friend base_name; \
234: using base_name::base_name
236: #endif // __cplusplus
238: #endif // IMPLDEVICEBASE_HPP