DNDSR 0.1.0.dev1+gcd065ad
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 "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 /// @brief Raw byte pointer to the underlying storage.
109 virtual uint8_t *raw_ptr() = 0;
110 /// @brief Copy `n_bytes` from `host_ptr` into this device buffer.
111 virtual void copy_host_to_device(uint8_t *host_ptr, size_t n_bytes) = 0;
112 /// @brief Copy `n_bytes` from this device buffer into `host_ptr`.
113 virtual void copy_device_to_host(uint8_t *host_ptr, size_t n_bytes) = 0;
114 /// @brief Device-to-device copy of `n_bytes` into `device_ptr_dst`.
115 virtual void copy_to_device(uint8_t *device_ptr_dst, size_t n_bytes) = 0;
116 //! =0 is a definition and all virtual functions must be defined to have vtable
117 //! never omit =0 or use {}
118 /// @brief Buffer size in bytes.
119 [[nodiscard]] virtual size_t bytes() const = 0;
120 /// @brief Which backend the buffer lives on.
121 [[nodiscard]] virtual DeviceBackend backend() const = 0;
123 };
124
125 /// @brief Compile-time-specialised storage class; one definition per @ref DNDS::DeviceBackend "DeviceBackend".
126 template <DeviceBackend B>
128
129 /// @brief Factory functions for constructing @ref DNDS::DeviceStorageBase "DeviceStorageBase" instances of
130 /// a specific backend. Specialised per backend so that the concrete type
131 /// creation can live in backend-specific translation units.
132 template <DeviceBackend B>
138
139 template <>
145/*
146 #define DNDS_DEVICE_STORAGE_INST(T, B, ext) \
147 ext template t_supDeviceStorageBase device_storage_factory<T, B>::device_storage_create_unique(DeviceBackend backend, size_t n_bytes); \
148 ext template t_sspDeviceStorageBase device_storage_factory<T, B>::device_storage_create_shared(DeviceBackend backend, size_t n_bytes);
149*/
150#ifdef DNDS_USE_CUDA
151 template <>
153 {
156 };
157
158#endif
160 /// @brief Top-level factory: dispatches to the per-backend factory based on
161 /// `backend`. Returns a null `unique_ptr` for @ref DNDS::DeviceBackend "DeviceBackend"::Unknown.
162 inline t_supDeviceStorageBase device_storage_create(DeviceBackend backend, size_t n_bytes)
163 {
164 switch (backend)
165 {
167 // return std::make_unique<DeviceStorage<T, DeviceBackend::Host>>(n_elem);
169#ifdef DNDS_USE_CUDA
170 case DeviceBackend::CUDA:
172#endif
174 {
175 DNDS_assert_info(false, "not implemented");
177 }
179 default:
181 }
182 }
183}
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:113
Abstract interface to a byte buffer owned by a specific backend.
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.
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.
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.
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)