DNDSR 0.2.1
Distributed Numeric Data Structure for CFV
Loading...
Searching...
No Matches
DeviceStorage.hpp
Go to the documentation of this file.
1#pragma once
2/// @file DeviceStorage.hpp
3/// @brief Device memory abstraction layer with backend-specific storage and factory creation.
4
5#include "DNDS/Errors.hpp"
6#include "DNDS/Defines.hpp"
7#include <cstddef>
8#include <cstdint>
9#include <memory>
10#include <type_traits>
11
12// #ifdef DNDS_USE_CUDA
13// #include <thrust/host_vector.h>
14// #include <thrust/device_vector.h>
15// #endif
16
17namespace DNDS
18{
19 /**
20 * @brief Enumerates the backends a @ref DNDS::DeviceStorage "DeviceStorage" / @ref DNDS::Array "Array" can live on.
21 *
22 * @details @ref Host is always available; @ref CUDA is compiled in when
23 * @ref DNDS_USE_CUDA is defined. Additional slots (@ref Custom1, ...) are
24 * placeholders for future backends (e.g., HIP, SYCL) that can be plugged
25 * in by providing new factory specialisations.
26 */
27 enum class DeviceBackend
28 {
29 Unknown = 0, ///< Unset / sentinel.
30 Host = 1, ///< Plain CPU memory.
31#ifdef DNDS_USE_CUDA
32 CUDA = 2, ///< NVIDIA CUDA device memory.
33#endif
34 Custom1 = 101, ///< Reserved slot for a project-specific backend.
35 };
36
37 // To extend backend:
38 // specialize DeviceStorage in separate header (like DeviceStorage_CUDA.cuh)
39 // specialize device_storage_factory in this header
40 // define the factory functions of device_storage_factory in separate header (like DeviceStorage_CUDA.cuh)
41 // extern declare explicit instantiations for basic types in this header
42 // implement explicit instantiations for basic types (like in DeviceStorage_CUDA.cu)
43 // explicit instantiation for needed other types
44
45 // To extend types:
46 // extern declare explicit instantiations, like Geom/PeriodicInfo.hpp
47 // implement explicit instantiations of Host code, like Geom/PeriodicInfo.cpp
48 // implement explicit instantiations of each needed device code, like Geom/PeriodicInfo.cu
49
50 /// @brief Canonical string name for a @ref DNDS::DeviceBackend "DeviceBackend" (used in log messages).
51 inline const char *device_backend_name(DeviceBackend B)
52 {
53 switch (B)
54 {
56 return "Host";
57#ifdef DNDS_USE_CUDA
58 case DeviceBackend::CUDA:
59 return "CUDA";
60#endif
62 return "Custom1";
64 default:
65 return "Unknown";
66 }
67 }
68
69 /// @brief Inverse of #device_backend_name. Returns @ref Unknown for unrecognised names.
70 inline DeviceBackend device_backend_name_to_enum(std::string_view s)
71 {
72 if (s == "Host")
74#ifdef DNDS_USE_CUDA
75 if (s == "CUDA")
76 return DeviceBackend::CUDA;
77#endif
79 }
80
81 class DeviceStorageBase;
82 /// @brief Stateless deleter for @ref DNDS::DeviceStorageBase "DeviceStorageBase" that works across shared-library
83 /// boundaries where the vtable of `unique_ptr`'s default deleter would not.
84 void deviceStorageBase_deleter(DeviceStorageBase *p); // safe deleter to maintain cross-DLL safety
85
86 /// @brief Owning unique pointer to a @ref DNDS::DeviceStorageBase "DeviceStorageBase" with cross-DLL-safe deleter.
87 using t_supDeviceStorageBase = std::unique_ptr<DeviceStorageBase, std::function<void(DeviceStorageBase *)>>;
88 /// @brief Shared pointer equivalent of #t_supDeviceStorageBase.
89 using t_sspDeviceStorageBase = std::shared_ptr<DeviceStorageBase>;
90
91 /// @brief Null-value helper for #t_supDeviceStorageBase.
96
97 /**
98 * @brief Abstract interface to a byte buffer owned by a specific backend.
99 *
100 * @details All DNDS device memory ultimately goes through this interface so
101 * that the higher-level `host_device_vector<T>` can be backend-agnostic.
102 * Concrete backends provide specialised @ref DNDS::DeviceStorage "DeviceStorage"<B> implementations;
103 * creation funnels through #device_storage_factory.
104 */
106 {
107 public:
108 // Polymorphic RAII base: each concrete subclass owns a device
109 // allocation. Callers manipulate instances via `unique_ptr` /
110 // `shared_ptr`, so slicing-unsafe copy / move are deleted.
111 DeviceStorageBase() = default;
116
117 /// @brief Raw byte pointer to the underlying storage.
118 virtual uint8_t *raw_ptr() = 0;
119 /// @brief Copy `n_bytes` from `host_ptr` into this device buffer.
120 virtual void copy_host_to_device(uint8_t *host_ptr, size_t n_bytes) = 0;
121 /// @brief Copy `n_bytes` from this device buffer into `host_ptr`.
122 virtual void copy_device_to_host(uint8_t *host_ptr, size_t n_bytes) = 0;
123 /// @brief Device-to-device copy of `n_bytes` into `device_ptr_dst`.
124 virtual void copy_to_device(uint8_t *device_ptr_dst, size_t n_bytes) = 0;
125 //! =0 is a definition and all virtual functions must be defined to have vtable
126 //! never omit =0 or use {}
127 /// @brief Buffer size in bytes.
128 [[nodiscard]] virtual size_t bytes() const = 0;
129 /// @brief Which backend the buffer lives on.
130 [[nodiscard]] virtual DeviceBackend backend() const = 0;
132 };
133
134 /// @brief Compile-time-specialised storage class; one definition per @ref DNDS::DeviceBackend "DeviceBackend".
135 template <DeviceBackend B>
137
138 /// @brief Factory functions for constructing @ref DNDS::DeviceStorageBase "DeviceStorageBase" instances of
139 /// a specific backend. Specialised per backend so that the concrete type
140 /// creation can live in backend-specific translation units.
141 template <DeviceBackend B>
147
148 template <>
154/*
155 #define DNDS_DEVICE_STORAGE_INST(T, B, ext) \
156 ext template t_supDeviceStorageBase device_storage_factory<T, B>::device_storage_create_unique(DeviceBackend backend, size_t n_bytes); \
157 ext template t_sspDeviceStorageBase device_storage_factory<T, B>::device_storage_create_shared(DeviceBackend backend, size_t n_bytes);
158*/
159#ifdef DNDS_USE_CUDA
160 template <>
162 {
165 };
166
167#endif
169 /// @brief Top-level factory: dispatches to the per-backend factory based on
170 /// `backend`. Returns a null `unique_ptr` for @ref DNDS::DeviceBackend "DeviceBackend"::Unknown.
171 inline t_supDeviceStorageBase device_storage_create(DeviceBackend backend, size_t n_bytes)
172 {
173 switch (backend)
174 {
176 // return std::make_unique<DeviceStorage<T, DeviceBackend::Host>>(n_elem);
178#ifdef DNDS_USE_CUDA
179 case DeviceBackend::CUDA:
181#endif
183 {
184 DNDS_assert_info(false, "not implemented");
186 }
188 default:
190 }
191 }
192}
Core type aliases, constants, and metaprogramming utilities for the DNDS framework.
Assertion / error-handling macros and supporting helper functions.
#define DNDS_assert_info(expr, info)
Debug-only assertion with an extra std::string info message.
Definition Errors.hpp:117
Abstract interface to a byte buffer owned by a specific backend.
DeviceStorageBase(const DeviceStorageBase &)=delete
virtual DeviceBackend backend() const =0
Which backend the buffer lives on.
virtual void copy_to_device(uint8_t *device_ptr_dst, size_t n_bytes)=0
Device-to-device copy of n_bytes into device_ptr_dst.
virtual uint8_t * raw_ptr()=0
Raw byte pointer to the underlying storage.
virtual size_t bytes() const =0
Buffer size in bytes.
DeviceStorageBase(DeviceStorageBase &&)=delete
virtual void copy_device_to_host(uint8_t *host_ptr, size_t n_bytes)=0
Copy n_bytes from this device buffer into host_ptr.
DeviceStorageBase & operator=(const DeviceStorageBase &)=delete
virtual void copy_host_to_device(uint8_t *host_ptr, size_t n_bytes)=0
Copy n_bytes from host_ptr into this device buffer.
DeviceStorageBase & operator=(DeviceStorageBase &&)=delete
Compile-time-specialised storage class; one definition per DeviceBackend.
the host side operators are provided as implemented
void deviceStorageBase_deleter(DeviceStorageBase *p)
Stateless deleter for DeviceStorageBase that works across shared-library boundaries where the vtable ...
t_supDeviceStorageBase device_storage_create(DeviceBackend backend, size_t n_bytes)
Top-level factory: dispatches to the per-backend factory based on backend. Returns a null unique_ptr ...
DeviceBackend
Enumerates the backends a DeviceStorage / Array can live on.
@ Unknown
Unset / sentinel.
@ Custom1
Reserved slot for a project-specific backend.
@ Host
Plain CPU memory.
const char * device_backend_name(DeviceBackend B)
Canonical string name for a DeviceBackend (used in log messages).
DeviceBackend device_backend_name_to_enum(std::string_view s)
Inverse of device_backend_name. Returns Unknown for unrecognised names.
std::unique_ptr< DeviceStorageBase, std::function< void(DeviceStorageBase *)> > t_supDeviceStorageBase
Owning unique pointer to a DeviceStorageBase with cross-DLL-safe deleter.
t_supDeviceStorageBase null_supDeviceStorageBase()
Null-value helper for t_supDeviceStorageBase.
std::shared_ptr< DeviceStorageBase > t_sspDeviceStorageBase
Shared pointer equivalent of t_supDeviceStorageBase.
Factory functions for constructing DeviceStorageBase instances of a specific backend....
static t_supDeviceStorageBase device_storage_create_unique(DeviceBackend backend, size_t n_bytes)
static t_sspDeviceStorageBase device_storage_create_shared(DeviceBackend backend, size_t n_bytes)
const tPoint const tPoint const tPoint & p