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