10e6b6b59SJacob Faibussowitsch #ifndef IMPLDEVICEBASE_HPP 20e6b6b59SJacob Faibussowitsch #define IMPLDEVICEBASE_HPP 30e6b6b59SJacob Faibussowitsch 40e6b6b59SJacob Faibussowitsch #if defined(__cplusplus) 50e6b6b59SJacob Faibussowitsch #include <petsc/private/deviceimpl.h> 60e6b6b59SJacob Faibussowitsch #include <petsc/private/viewerimpl.h> 70e6b6b59SJacob Faibussowitsch 80e6b6b59SJacob Faibussowitsch #include <petsc/private/cpp/crtp.hpp> 90e6b6b59SJacob Faibussowitsch #include <petsc/private/cpp/type_traits.hpp> 100e6b6b59SJacob Faibussowitsch #include <petsc/private/cpp/utility.hpp> 110e6b6b59SJacob Faibussowitsch #include <petsc/private/cpp/array.hpp> 120e6b6b59SJacob Faibussowitsch 130e6b6b59SJacob Faibussowitsch #include <cstring> // for std::strlen 140e6b6b59SJacob Faibussowitsch 15*d71ae5a4SJacob Faibussowitsch namespace Petsc 16*d71ae5a4SJacob Faibussowitsch { 170e6b6b59SJacob Faibussowitsch 18*d71ae5a4SJacob Faibussowitsch namespace device 19*d71ae5a4SJacob Faibussowitsch { 200e6b6b59SJacob Faibussowitsch 21*d71ae5a4SJacob Faibussowitsch namespace impl 22*d71ae5a4SJacob Faibussowitsch { 230e6b6b59SJacob Faibussowitsch 240e6b6b59SJacob Faibussowitsch template <typename Derived> // CRTP 250e6b6b59SJacob Faibussowitsch class DeviceBase : public util::crtp<Derived, DeviceBase> { 260e6b6b59SJacob Faibussowitsch public: 270e6b6b59SJacob Faibussowitsch using derived_type = Derived; 280e6b6b59SJacob Faibussowitsch using createContextFunction_t = PetscErrorCode (*)(PetscDeviceContext); 290e6b6b59SJacob Faibussowitsch 300e6b6b59SJacob Faibussowitsch // default constructor 310e6b6b59SJacob Faibussowitsch constexpr DeviceBase(createContextFunction_t f) noexcept : create_(f) { } 320e6b6b59SJacob Faibussowitsch 330e6b6b59SJacob Faibussowitsch template <typename T = derived_type> 34*d71ae5a4SJacob Faibussowitsch PETSC_NODISCARD static constexpr PetscDeviceType PETSC_DEVICE_IMPL() noexcept 35*d71ae5a4SJacob Faibussowitsch { 360e6b6b59SJacob Faibussowitsch return T::PETSC_DEVICE_IMPL_(); 370e6b6b59SJacob Faibussowitsch } 380e6b6b59SJacob Faibussowitsch 390e6b6b59SJacob Faibussowitsch PETSC_NODISCARD PetscErrorCode getDevice(PetscDevice, PetscInt) noexcept; 400e6b6b59SJacob Faibussowitsch PETSC_NODISCARD static PetscErrorCode configureDevice(PetscDevice) noexcept; 410e6b6b59SJacob Faibussowitsch PETSC_NODISCARD static PetscErrorCode viewDevice(PetscDevice, PetscViewer) noexcept; 420e6b6b59SJacob Faibussowitsch PETSC_NODISCARD static PetscErrorCode getAttribute(PetscDevice, PetscDeviceAttribute, void *) noexcept; 430e6b6b59SJacob Faibussowitsch 440e6b6b59SJacob Faibussowitsch protected: 450e6b6b59SJacob Faibussowitsch // function to create a PetscDeviceContext (the (*create) function pointer usually set 460e6b6b59SJacob Faibussowitsch // via XXXSetType() for other PETSc objects) 470e6b6b59SJacob Faibussowitsch const createContextFunction_t create_; 480e6b6b59SJacob Faibussowitsch 490e6b6b59SJacob Faibussowitsch // if you want the base class to handle the entire options query, has the same arguments as 500e6b6b59SJacob Faibussowitsch // PetscOptionDeviceBasic 510e6b6b59SJacob Faibussowitsch PETSC_NODISCARD static PetscErrorCode PetscOptionDeviceAll(MPI_Comm, std::pair<PetscDeviceInitType, PetscBool> &, std::pair<PetscInt, PetscBool> &, std::pair<PetscBool, PetscBool> &) noexcept; 520e6b6b59SJacob Faibussowitsch 530e6b6b59SJacob Faibussowitsch // if you want to start and end the options query yourself, but still want all the default 540e6b6b59SJacob Faibussowitsch // options 550e6b6b59SJacob Faibussowitsch PETSC_NODISCARD static PetscErrorCode PetscOptionDeviceBasic(PetscOptionItems *, std::pair<PetscDeviceInitType, PetscBool> &, std::pair<PetscInt, PetscBool> &, std::pair<PetscBool, PetscBool> &) noexcept; 560e6b6b59SJacob Faibussowitsch 570e6b6b59SJacob Faibussowitsch // option templates to follow, each one has two forms: 580e6b6b59SJacob Faibussowitsch // - A simple form returning only the value and flag. This gives no control over the message, 590e6b6b59SJacob Faibussowitsch // arguments to the options query or otherwise 600e6b6b59SJacob Faibussowitsch // - A complex form, which allows you to pass most of the options query arguments *EXCEPT* 610e6b6b59SJacob Faibussowitsch // - The options query function called 620e6b6b59SJacob Faibussowitsch // - The option string 630e6b6b59SJacob Faibussowitsch 640e6b6b59SJacob Faibussowitsch // option template for initializing the device 650e6b6b59SJacob Faibussowitsch PETSC_NODISCARD static PetscErrorCode PetscOptionDeviceInitialize(PetscOptionItems *, PetscDeviceInitType *, PetscBool *) noexcept; 660e6b6b59SJacob Faibussowitsch template <typename... T, util::enable_if_t<sizeof...(T) >= 3, int> = 0> 670e6b6b59SJacob Faibussowitsch PETSC_NODISCARD static PetscErrorCode PetscOptionDeviceInitialize(PetscOptionItems *, T &&...) noexcept; 680e6b6b59SJacob Faibussowitsch // option template for selecting the default device 690e6b6b59SJacob Faibussowitsch PETSC_NODISCARD static PetscErrorCode PetscOptionDeviceSelect(PetscOptionItems *, PetscInt *, PetscBool *) noexcept; 700e6b6b59SJacob Faibussowitsch template <typename... T, util::enable_if_t<sizeof...(T) >= 3, int> = 0> 710e6b6b59SJacob Faibussowitsch PETSC_NODISCARD static PetscErrorCode PetscOptionDeviceSelect(PetscOptionItems *, T &&...) noexcept; 720e6b6b59SJacob Faibussowitsch // option templates for viewing a device 730e6b6b59SJacob Faibussowitsch PETSC_NODISCARD static PetscErrorCode PetscOptionDeviceView(PetscOptionItems *, PetscBool *, PetscBool *) noexcept; 740e6b6b59SJacob Faibussowitsch template <typename... T, util::enable_if_t<sizeof...(T) >= 3, int> = 0> 750e6b6b59SJacob Faibussowitsch PETSC_NODISCARD static PetscErrorCode PetscOptionDeviceView(PetscOptionItems *, T &&...) noexcept; 760e6b6b59SJacob Faibussowitsch 770e6b6b59SJacob Faibussowitsch private: 780e6b6b59SJacob Faibussowitsch // base function for all options templates above, they basically just reformat the arguments, 790e6b6b59SJacob Faibussowitsch // create the option string and pass it off to this function 800e6b6b59SJacob Faibussowitsch template <typename... T, typename F = PetscErrorCode (*)(PetscOptionItems *, const char *, T &&...)> 810e6b6b59SJacob Faibussowitsch PETSC_NODISCARD static PetscErrorCode PetscOptionDevice(F &&, PetscOptionItems *, const char[], T &&...) noexcept; 820e6b6b59SJacob Faibussowitsch 830e6b6b59SJacob Faibussowitsch // default crtp implementations 84*d71ae5a4SJacob Faibussowitsch PETSC_NODISCARD static PetscErrorCode init_device_id_(PetscInt *id) noexcept 85*d71ae5a4SJacob Faibussowitsch { 860e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 870e6b6b59SJacob Faibussowitsch *id = 0; 880e6b6b59SJacob Faibussowitsch PetscFunctionReturn(0); 890e6b6b59SJacob Faibussowitsch } 900e6b6b59SJacob Faibussowitsch 910e6b6b59SJacob Faibussowitsch PETSC_NODISCARD static constexpr PetscErrorCode configure_device_(PetscDevice) noexcept { return 0; } 920e6b6b59SJacob Faibussowitsch PETSC_NODISCARD static constexpr PetscErrorCode view_device_(PetscDevice, PetscViewer) noexcept { return 0; } 930e6b6b59SJacob Faibussowitsch }; 940e6b6b59SJacob Faibussowitsch 950e6b6b59SJacob Faibussowitsch template <typename D> 96*d71ae5a4SJacob Faibussowitsch inline PetscErrorCode DeviceBase<D>::getDevice(PetscDevice device, PetscInt id) noexcept 97*d71ae5a4SJacob Faibussowitsch { 980e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 990e6b6b59SJacob Faibussowitsch PetscCall(this->underlying().init_device_id_(&id)); 1000e6b6b59SJacob Faibussowitsch device->deviceId = id; 1010e6b6b59SJacob Faibussowitsch device->ops->createcontext = this->underlying().create_; 1020e6b6b59SJacob Faibussowitsch device->ops->configure = this->underlying().configureDevice; 1030e6b6b59SJacob Faibussowitsch device->ops->view = this->underlying().viewDevice; 1040e6b6b59SJacob Faibussowitsch device->ops->getattribute = this->underlying().getAttribute; 1050e6b6b59SJacob Faibussowitsch PetscFunctionReturn(0); 1060e6b6b59SJacob Faibussowitsch } 1070e6b6b59SJacob Faibussowitsch 1080e6b6b59SJacob Faibussowitsch template <typename D> 109*d71ae5a4SJacob Faibussowitsch inline PetscErrorCode DeviceBase<D>::configureDevice(PetscDevice device) noexcept 110*d71ae5a4SJacob Faibussowitsch { 1110e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 1120e6b6b59SJacob Faibussowitsch PetscCall(derived_type::configure_device_(device)); 1130e6b6b59SJacob Faibussowitsch PetscFunctionReturn(0); 1140e6b6b59SJacob Faibussowitsch } 1150e6b6b59SJacob Faibussowitsch 1160e6b6b59SJacob Faibussowitsch template <typename D> 117*d71ae5a4SJacob Faibussowitsch inline PetscErrorCode DeviceBase<D>::viewDevice(PetscDevice device, PetscViewer viewer) noexcept 118*d71ae5a4SJacob Faibussowitsch { 1190e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 1200e6b6b59SJacob Faibussowitsch PetscCall(derived_type::view_device_(device, viewer)); 1210e6b6b59SJacob Faibussowitsch PetscFunctionReturn(0); 1220e6b6b59SJacob Faibussowitsch } 1230e6b6b59SJacob Faibussowitsch 1240e6b6b59SJacob Faibussowitsch template <typename D> 125*d71ae5a4SJacob Faibussowitsch inline PetscErrorCode DeviceBase<D>::getAttribute(PetscDevice device, PetscDeviceAttribute attr, void *value) noexcept 126*d71ae5a4SJacob Faibussowitsch { 1270e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 1280e6b6b59SJacob Faibussowitsch PetscCall(derived_type::get_attribute_(device->deviceId, attr, value)); 1290e6b6b59SJacob Faibussowitsch PetscFunctionReturn(0); 1300e6b6b59SJacob Faibussowitsch } 1310e6b6b59SJacob Faibussowitsch 1320e6b6b59SJacob Faibussowitsch template <typename D> 1330e6b6b59SJacob Faibussowitsch template <typename... T, typename F> 134*d71ae5a4SJacob Faibussowitsch inline PetscErrorCode DeviceBase<D>::PetscOptionDevice(F &&OptionsFunction, PetscOptionItems *PetscOptionsObject, const char optstub[], T &&...args) noexcept 135*d71ae5a4SJacob Faibussowitsch { 1360e6b6b59SJacob Faibussowitsch constexpr auto dtype = PETSC_DEVICE_IMPL(); 1370e6b6b59SJacob Faibussowitsch const auto implname = PetscDeviceTypes[dtype]; 1380e6b6b59SJacob Faibussowitsch auto buf = std::array<char, 128>{}; 1390e6b6b59SJacob Faibussowitsch constexpr auto buflen = buf.size() - 1; 1400e6b6b59SJacob Faibussowitsch 1410e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 1420e6b6b59SJacob Faibussowitsch if (PetscDefined(USE_DEBUG)) { 1430e6b6b59SJacob Faibussowitsch const auto len = std::strlen(optstub) + std::strlen(implname); 1440e6b6b59SJacob Faibussowitsch 1450e6b6b59SJacob 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); 1460e6b6b59SJacob Faibussowitsch } 1470e6b6b59SJacob Faibussowitsch PetscCall(PetscSNPrintf(buf.data(), buflen, "%s%s", optstub, implname)); 1480e6b6b59SJacob Faibussowitsch PetscCall(OptionsFunction(PetscOptionsObject, buf.data(), std::forward<T>(args)...)); 1490e6b6b59SJacob Faibussowitsch PetscFunctionReturn(0); 1500e6b6b59SJacob Faibussowitsch } 1510e6b6b59SJacob Faibussowitsch 1520e6b6b59SJacob Faibussowitsch template <typename D> 1530e6b6b59SJacob Faibussowitsch template <typename... T, util::enable_if_t<sizeof...(T) >= 3, int>> 154*d71ae5a4SJacob Faibussowitsch inline PetscErrorCode DeviceBase<D>::PetscOptionDeviceInitialize(PetscOptionItems *PetscOptionsObject, T &&...args) noexcept 155*d71ae5a4SJacob Faibussowitsch { 1560e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 1570e6b6b59SJacob Faibussowitsch PetscCall(PetscOptionDevice(PetscOptionsEList_Private, PetscOptionsObject, "-device_enable_", std::forward<T>(args)...)); 1580e6b6b59SJacob Faibussowitsch PetscFunctionReturn(0); 1590e6b6b59SJacob Faibussowitsch } 1600e6b6b59SJacob Faibussowitsch 1610e6b6b59SJacob Faibussowitsch template <typename D> 162*d71ae5a4SJacob Faibussowitsch inline PetscErrorCode DeviceBase<D>::PetscOptionDeviceInitialize(PetscOptionItems *PetscOptionsObject, PetscDeviceInitType *inittype, PetscBool *flag) noexcept 163*d71ae5a4SJacob Faibussowitsch { 1640e6b6b59SJacob Faibussowitsch auto type = static_cast<PetscInt>(util::integral_value(*inittype)); 1650e6b6b59SJacob Faibussowitsch 1660e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 1670e6b6b59SJacob Faibussowitsch PetscCall(PetscOptionDeviceInitialize(PetscOptionsObject, "How (or whether) to initialize a device", "PetscDeviceInitialize()", PetscDeviceInitTypes, 3, PetscDeviceInitTypes[type], &type, flag)); 1680e6b6b59SJacob Faibussowitsch *inittype = static_cast<PetscDeviceInitType>(type); 1690e6b6b59SJacob Faibussowitsch PetscFunctionReturn(0); 1700e6b6b59SJacob Faibussowitsch } 1710e6b6b59SJacob Faibussowitsch 1720e6b6b59SJacob Faibussowitsch template <typename D> 1730e6b6b59SJacob Faibussowitsch template <typename... T, util::enable_if_t<sizeof...(T) >= 3, int>> 174*d71ae5a4SJacob Faibussowitsch inline PetscErrorCode DeviceBase<D>::PetscOptionDeviceSelect(PetscOptionItems *PetscOptionsObject, T &&...args) noexcept 175*d71ae5a4SJacob Faibussowitsch { 1760e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 1770e6b6b59SJacob Faibussowitsch PetscCall(PetscOptionDevice(PetscOptionsInt_Private, PetscOptionsObject, "-device_select_", std::forward<T>(args)...)); 1780e6b6b59SJacob Faibussowitsch PetscFunctionReturn(0); 1790e6b6b59SJacob Faibussowitsch } 1800e6b6b59SJacob Faibussowitsch 1810e6b6b59SJacob Faibussowitsch template <typename D> 182*d71ae5a4SJacob Faibussowitsch inline PetscErrorCode DeviceBase<D>::PetscOptionDeviceSelect(PetscOptionItems *PetscOptionsObject, PetscInt *id, PetscBool *flag) noexcept 183*d71ae5a4SJacob Faibussowitsch { 1840e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 1850e6b6b59SJacob 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)); 1860e6b6b59SJacob Faibussowitsch PetscFunctionReturn(0); 1870e6b6b59SJacob Faibussowitsch } 1880e6b6b59SJacob Faibussowitsch 1890e6b6b59SJacob Faibussowitsch template <typename D> 1900e6b6b59SJacob Faibussowitsch template <typename... T, util::enable_if_t<sizeof...(T) >= 3, int>> 191*d71ae5a4SJacob Faibussowitsch inline PetscErrorCode DeviceBase<D>::PetscOptionDeviceView(PetscOptionItems *PetscOptionsObject, T &&...args) noexcept 192*d71ae5a4SJacob Faibussowitsch { 1930e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 1940e6b6b59SJacob Faibussowitsch PetscCall(PetscOptionDevice(PetscOptionsBool_Private, PetscOptionsObject, "-device_view_", std::forward<T>(args)...)); 1950e6b6b59SJacob Faibussowitsch PetscFunctionReturn(0); 1960e6b6b59SJacob Faibussowitsch } 1970e6b6b59SJacob Faibussowitsch 1980e6b6b59SJacob Faibussowitsch template <typename D> 199*d71ae5a4SJacob Faibussowitsch inline PetscErrorCode DeviceBase<D>::PetscOptionDeviceView(PetscOptionItems *PetscOptionsObject, PetscBool *view, PetscBool *flag) noexcept 200*d71ae5a4SJacob Faibussowitsch { 2010e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 2020e6b6b59SJacob Faibussowitsch PetscCall(PetscOptionDeviceView(PetscOptionsObject, "Display device information and assignments (forces eager initialization)", "PetscDeviceView()", *view, view, flag)); 2030e6b6b59SJacob Faibussowitsch PetscFunctionReturn(0); 2040e6b6b59SJacob Faibussowitsch } 2050e6b6b59SJacob Faibussowitsch 2060e6b6b59SJacob Faibussowitsch template <typename D> 207*d71ae5a4SJacob Faibussowitsch inline PetscErrorCode DeviceBase<D>::PetscOptionDeviceBasic(PetscOptionItems *PetscOptionsObject, std::pair<PetscDeviceInitType, PetscBool> &initType, std::pair<PetscInt, PetscBool> &initId, std::pair<PetscBool, PetscBool> &initView) noexcept 208*d71ae5a4SJacob Faibussowitsch { 2090e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 2100e6b6b59SJacob Faibussowitsch PetscCall(PetscOptionDeviceInitialize(PetscOptionsObject, &initType.first, &initType.second)); 2110e6b6b59SJacob Faibussowitsch PetscCall(PetscOptionDeviceSelect(PetscOptionsObject, &initId.first, &initId.second)); 2120e6b6b59SJacob Faibussowitsch PetscCall(PetscOptionDeviceView(PetscOptionsObject, &initView.first, &initView.second)); 2130e6b6b59SJacob Faibussowitsch PetscFunctionReturn(0); 2140e6b6b59SJacob Faibussowitsch } 2150e6b6b59SJacob Faibussowitsch 2160e6b6b59SJacob Faibussowitsch template <typename D> 217*d71ae5a4SJacob 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 218*d71ae5a4SJacob Faibussowitsch { 2190e6b6b59SJacob Faibussowitsch constexpr char optname[] = "PetscDevice %s Options"; 2200e6b6b59SJacob Faibussowitsch constexpr auto dtype = PETSC_DEVICE_IMPL(); 2210e6b6b59SJacob Faibussowitsch const auto implname = PetscDeviceTypes[dtype]; 2220e6b6b59SJacob Faibussowitsch auto buf = std::array<char, 128>{}; 2230e6b6b59SJacob Faibussowitsch constexpr auto buflen = buf.size() - 1; // -1 to leave room for null 2240e6b6b59SJacob Faibussowitsch 2250e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 2260e6b6b59SJacob Faibussowitsch if (PetscDefined(USE_DEBUG)) { 2270e6b6b59SJacob Faibussowitsch // -3 since '%s' is replaced and dont count null char for optname 2280e6b6b59SJacob Faibussowitsch const auto len = std::strlen(implname) + PETSC_STATIC_ARRAY_LENGTH(optname) - 3; 2290e6b6b59SJacob Faibussowitsch 2300e6b6b59SJacob 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); 2310e6b6b59SJacob Faibussowitsch } 2320e6b6b59SJacob Faibussowitsch PetscCall(PetscSNPrintf(buf.data(), buflen, optname, implname)); 2330e6b6b59SJacob Faibussowitsch PetscOptionsBegin(comm, nullptr, buf.data(), "Sys"); 2340e6b6b59SJacob Faibussowitsch PetscCall(PetscOptionDeviceBasic(PetscOptionsObject, initType, initId, initView)); 2350e6b6b59SJacob Faibussowitsch PetscOptionsEnd(); 2360e6b6b59SJacob Faibussowitsch PetscFunctionReturn(0); 2370e6b6b59SJacob Faibussowitsch } 2380e6b6b59SJacob Faibussowitsch 2390e6b6b59SJacob Faibussowitsch } // namespace impl 2400e6b6b59SJacob Faibussowitsch 2410e6b6b59SJacob Faibussowitsch } // namespace device 2420e6b6b59SJacob Faibussowitsch 2430e6b6b59SJacob Faibussowitsch } // namespace Petsc 2440e6b6b59SJacob Faibussowitsch 2450e6b6b59SJacob Faibussowitsch #define PETSC_DEVICE_IMPL_BASE_CLASS_HEADER(base_name, T) \ 2460e6b6b59SJacob Faibussowitsch using base_name = ::Petsc::device::impl::DeviceBase<T>; \ 2470e6b6b59SJacob Faibussowitsch friend base_name; \ 2480e6b6b59SJacob Faibussowitsch using base_name::base_name 2490e6b6b59SJacob Faibussowitsch 2500e6b6b59SJacob Faibussowitsch #endif // __cplusplus 2510e6b6b59SJacob Faibussowitsch 2520e6b6b59SJacob Faibussowitsch #endif // IMPLDEVICEBASE_HPP 253