Loading...
Searching...
No Matches
device_backend.h
Go to the documentation of this file.
1// SPDX-License-Identifier: AGPL-3.0-only
2// Copyright (C) 2026 Artificial Intelligence Techniques, S.L. and Roberto López González
3
4#pragma once
5
6#include <array>
7#include <utility>
8
11
12namespace opennn
13{
14
15template<typename Handle>
17{
18 Handle handle = nullptr;
19#ifdef OPENNN_HAS_CUDA
20 DnnStatus (*deleter)(Handle) = nullptr;
21#else
22 void (*deleter)(Handle) = nullptr;
23#endif
24
25 CudnnDescriptor() = default;
26
28 : handle(std::exchange(other.handle, nullptr)),
29 deleter(std::exchange(other.deleter, nullptr)) {}
30
32 {
33 if (this != &other)
34 {
35 reset();
36 handle = std::exchange(other.handle, nullptr);
37 deleter = std::exchange(other.deleter, nullptr);
38 }
39 return *this;
40 }
41
44
46
47 void reset()
48 {
50 handle = nullptr;
51 deleter = nullptr;
52 }
53
54 Handle get() const noexcept { return handle; }
55 operator Handle() const noexcept { return handle; }
56 explicit operator bool() const noexcept { return handle != nullptr; }
57};
58
59}
60
61namespace opennn::device
62{
63
71
72constexpr bool is_cuda_build() noexcept
73{
74#ifdef OPENNN_HAS_CUDA
75 return true;
76#else
77 return false;
78#endif
79}
80bool has_cuda_device() noexcept;
81
82// Why has_cuda_device() is false, in words a user can act on: no NVIDIA
83// driver, a driver older than the CUDA this build needs (with both versions),
84// no card, or the error CUDA gave. Empty when a device is available.
85string cuda_unavailable_reason() noexcept;
88string gpu_info_string() noexcept;
89
90// Where tuned cuBLASLt plans persist for this card and library, or empty when
91// the cache is disabled, there is no CUDA device, or the build has no CUDA.
92string lt_plan_cache_directory() noexcept;
94void set_cuda_allocation_growth_forbidden(bool forbidden) noexcept;
95void begin_cuda_shutdown() noexcept;
96
110
111inline constexpr std::array<const char*, static_cast<size_t>(GraphWorkspaceKind::Count)>
112graph_workspace_labels = {"shared_scratch", "bf16_input", "bf16_gradient",
113 "bf16_to_fp32", "int8_dequant", "pooling_mask", "norm_partials",
114 "gradient_partials", "flash_attention"};
115
117{
118 void* data = nullptr;
119 Index bytes = 0;
120};
121
122using GraphWorkspaceRequirements = std::array<Index, static_cast<size_t>(GraphWorkspaceKind::Count)>;
123using GraphWorkspaceViews = std::array<GraphWorkspaceView, static_cast<size_t>(GraphWorkspaceKind::Count)>;
124
125#ifdef OPENNN_HAS_CUDA
127optional<void*> graph_workspace_override(GraphWorkspaceKind, Index minimum_bytes);
128#endif
129
131{
132public:
134 const GraphWorkspaceViews* = nullptr);
135
138
140
141private:
142 GraphWorkspaceRequirements* previous_requirements = nullptr;
143 const GraphWorkspaceViews* previous_views = nullptr;
144 GraphWorkspaceViews owned_views;
145};
146
147int64_t conv_workspace_limit_bytes() noexcept;
148void set_conv_workspace_cap(int64_t mode) noexcept;
150
151bool conv_autotune_enabled() noexcept;
152void set_conv_autotune(bool enabled) noexcept;
153
154// TF32 for the fp32 paths on tensor cores: cuBLAS/cuBLASLt fp32 GEMMs and
155// cuDNN fp32 convolution engines. On by default (OPENNN_ALLOW_TF32=0 turns it
156// off), which is also PyTorch's setting in the benchmark. Off means IEEE fp32
157// arithmetic at several times the cost, and it exists for exactly one reason:
158// validating a GPU result against a CPU reference to a tolerance TF32's
159// 10-bit mantissa cannot meet. Takes effect on cuBLAS handles already created
160// and on plans built after the call; cached plans carry the setting in their
161// keys.
162bool allow_tf32() noexcept;
163void set_allow_tf32(bool enabled) noexcept;
165
170
171template<typename Rung> Rung rung() noexcept;
172template<typename Rung> void set_rung(Rung) noexcept;
173
175{
176public:
177
178 explicit CudaAllocationGrowthGuard(bool enabled,
179 bool forbid_matmul_plan_creation = true);
180
183
185
186private:
187 bool active = false;
188 bool previous = false;
189 bool guard_matmul_plans = false;
190 bool previous_matmul_plan_guard = false;
191};
192
193void* allocate(Device, Index);
194void deallocate(Device, void*, Index) noexcept;
195
196// Explicit session trimming returns only the caller's released blocks to CUDA.
198{
199public:
203 CudaBlockCacheBypass& operator=(const CudaBlockCacheBypass&) = delete;
204private:
205 bool previous;
206};
207
208void set_zero(void*, Index, Device);
209void set_zero_async(void*, Index, DeviceStream = nullptr);
210
211void copy_async(void*, const void*, Index, CopyKind, DeviceStream = nullptr);
212void copy_async(void*, const void*, Index, Device, Device, DeviceStream = nullptr);
213void synchronize(DeviceStream = nullptr);
215void reset_last_error() noexcept;
216
217#ifdef OPENNN_HAS_CUDA
219{
220public:
221
223
226
228
229private:
230
231 BlasHandle handle = nullptr;
232 BlasPointerMode previous_mode = CUBLAS_POINTER_MODE_HOST;
233};
234
236{
237public:
238
240
243
245
246private:
247
248 BlasHandle handle = nullptr;
249 BlasMathMode previous_mode = CUBLAS_DEFAULT_MATH;
250};
251#endif
252
254{
255public:
256
257 PinnedBuffer() = default;
258 explicit PinnedBuffer(Index byte_count);
259
260 PinnedBuffer(const PinnedBuffer&) = delete;
262
264 PinnedBuffer& operator=(PinnedBuffer&&) noexcept;
265
266 ~PinnedBuffer() noexcept;
267
268 void resize_bytes(Index);
269 void grow_to(Index);
270
271 void* data() noexcept { return pointer; }
272 const void* data() const noexcept { return pointer; }
273
274 template<typename T>
275 T* as() noexcept { return static_cast<T*>(pointer); }
276
277 template<typename T>
278 const T* as() const noexcept { return static_cast<const T*>(pointer); }
279
280 Index byte_size() const noexcept { return allocated_bytes; }
281 bool empty() const noexcept { return allocated_bytes == 0; }
282 explicit operator bool() const noexcept { return pointer != nullptr; }
283
284private:
285
286 void reset() noexcept;
287 void swap(PinnedBuffer&) noexcept;
288
289 void* pointer = nullptr;
290 Index allocated_bytes = 0;
291};
292
296
298{
299public:
300
301 CudaEvent() = default;
302 explicit CudaEvent(unsigned flags);
303
304 CudaEvent(const CudaEvent&) = delete;
305 CudaEvent& operator=(const CudaEvent&) = delete;
306
307 CudaEvent(CudaEvent&&) noexcept;
308 CudaEvent& operator=(CudaEvent&&) noexcept;
309
310 ~CudaEvent() noexcept;
311
312 void create();
313
314 DeviceEvent get() const noexcept { return handle; }
315 explicit operator bool() const noexcept { return handle != nullptr; }
316
317private:
318
319 void reset() noexcept;
320
321 DeviceEvent handle = nullptr;
322};
323
324struct GraphExecDeleter { void operator()(DeviceGraphExec) const noexcept; };
325
326using GraphExecHandle = unique_ptr<remove_pointer_t<DeviceGraphExec>, GraphExecDeleter>;
327
329{
330public:
332
333 StreamCapture(const StreamCapture&) = delete;
335
336 ~StreamCapture() noexcept;
337
339
340private:
341#ifdef OPENNN_HAS_CUDA
342 DeviceStream stream = nullptr;
343 bool finished = false;
344#endif
345};
346
348
349constexpr int MAX_LANES = 4;
350int lanes_available() noexcept;
351int active_lane() noexcept;
352void set_active_lane(int lane);
354
357
362
363}
364
365namespace opennn
366{
367
368ThreadPoolDevice& get_device();
370
371struct TensorView;
372
374template<typename T>
376{
377 return static_cast<T*>(ensure_workspace_bytes(kind, count * Index(sizeof(T))));
378}
384
386
388
389const void* bias_for_gemm_bf16(const TensorView&);
390
391// D = alpha * op(A) * op(B) + beta * C, with C the addend when one is given
392// and D itself otherwise -- the two scalars the wrapper used to hardcode as
393// &one and &zero. lda, ldb and ldd are 0 for "derive from m, n and k", which
394// is what it did before they were parameters. The operands carry a type each
395// because gemm_strided_batched_cuda below already takes an Atype and a Btype:
396// nothing can move off that call and onto this one until this one can say the
397// same thing.
399 int, int, int,
400 BlasOperation transA,
401 BlasOperation transB,
402 LinearEpilogue epilogue,
403 const void*, const void*, void*,
404 const void*,
405 DeviceDataType dtype_a = CUDA_R_32F,
406 DeviceDataType dtype_b = CUDA_R_32F,
407 DeviceDataType out_dtype = CUDA_R_32F,
408 const void* aux_pointer = nullptr,
409 const void* addend = nullptr,
410 float alpha = 1.0f,
411 float beta = 0.0f,
412 int lda = 0, int ldb = 0, int ldd = 0);
413
415 int, int, int,
416 const void*, DeviceDataType Atype, int, long long stride_a,
417 const void*, DeviceDataType Btype, int, long long stride_b,
418 void*, DeviceDataType Ctype, int, long long stride_c,
419 int,
420 float alpha = 1.0f, float beta = 0.0f);
421
422}
CublasMathModeGuard(BlasHandle, BlasMathMode)
CublasMathModeGuard(const CublasMathModeGuard &)=delete
CublasMathModeGuard & operator=(const CublasMathModeGuard &)=delete
CublasPointerModeGuard(const CublasPointerModeGuard &)=delete
CublasPointerModeGuard(BlasHandle, BlasPointerMode)
CublasPointerModeGuard & operator=(const CublasPointerModeGuard &)=delete
CudaAllocationGrowthGuard(const CudaAllocationGrowthGuard &)=delete
CudaAllocationGrowthGuard & operator=(const CudaAllocationGrowthGuard &)=delete
CudaAllocationGrowthGuard(bool enabled, bool forbid_matmul_plan_creation=true)
DeviceEvent get() const noexcept
Definition device_backend.h:314
CudaEvent(const CudaEvent &)=delete
CudaEvent(CudaEvent &&) noexcept
CudaEvent & operator=(const CudaEvent &)=delete
CudaEvent(unsigned flags)
CudaGraphWorkspaceScope(GraphWorkspaceRequirements &, const GraphWorkspaceViews *=nullptr)
CudaGraphWorkspaceScope(const CudaGraphWorkspaceScope &)=delete
CudaGraphWorkspaceScope & operator=(const CudaGraphWorkspaceScope &)=delete
Definition device_backend.h:254
bool empty() const noexcept
Definition device_backend.h:281
PinnedBuffer(Index byte_count)
T * as() noexcept
Definition device_backend.h:275
PinnedBuffer(const PinnedBuffer &)=delete
void * data() noexcept
Definition device_backend.h:271
const void * data() const noexcept
Definition device_backend.h:272
Index byte_size() const noexcept
Definition device_backend.h:280
const T * as() const noexcept
Definition device_backend.h:278
PinnedBuffer & operator=(const PinnedBuffer &)=delete
PinnedBuffer(PinnedBuffer &&) noexcept
StreamCapture & operator=(const StreamCapture &)=delete
StreamCapture(const StreamCapture &)=delete
void end(GraphExecHandle &)
Definition energy_meter.h:7
bool conv_autotune_enabled() noexcept
constexpr int MAX_LANES
Definition device_backend.h:349
void set_zero(void *, Index, Device)
AttentionRung
Definition device_backend.h:169
bool has_cuda_device() noexcept
std::array< GraphWorkspaceView, static_cast< size_t >(GraphWorkspaceKind::Count)> GraphWorkspaceViews
Definition device_backend.h:123
void stream_wait_event(DeviceStream, DeviceEvent)
void synchronize_event(DeviceEvent)
string cuda_unavailable_reason() noexcept
void begin_cuda_shutdown() noexcept
void copy_async(void *, const void *, Index, CopyKind, DeviceStream=nullptr)
Rung rung() noexcept
bool cuda_matmul_plan_creation_forbidden() noexcept
bool allow_tf32() noexcept
void set_cuda_allocation_growth_forbidden(bool forbidden) noexcept
string lt_plan_cache_directory() noexcept
BlasLtHandle get_cublas_lt_handle()
void * allocate(Device, Index)
DnnHandle get_cudnn_handle()
int active_lane() noexcept
DeviceStream lane_stream(int lane)
BatchNormForwardRung
Definition device_backend.h:167
@ CudnnGraph
Definition device_backend.h:167
void set_active_lane(int lane)
void set_conv_workspace_cap(int64_t mode) noexcept
void set_conv_autotune(bool enabled) noexcept
string gpu_info_string() noexcept
void set_rung(Rung) noexcept
optional< void * > graph_workspace_override(GraphWorkspaceKind, Index minimum_bytes)
int cuda_compute_capability() noexcept
bool cuda_allocation_growth_forbidden() noexcept
DeviceStream get_compute_stream()
void record_event(DeviceEvent, DeviceStream)
void deallocate(Device, void *, Index) noexcept
unique_ptr< remove_pointer_t< DeviceGraphExec >, GraphExecDeleter > GraphExecHandle
Definition device_backend.h:326
void refresh_blas_math_mode()
DeviceStream get_transfer_stream()
void set_zero_async(void *, Index, DeviceStream=nullptr)
void set_allow_tf32(bool enabled) noexcept
size_t available_memory()
std::array< Index, static_cast< size_t >(GraphWorkspaceKind::Count)> GraphWorkspaceRequirements
Definition device_backend.h:122
GraphWorkspaceKind
Definition device_backend.h:98
@ FlashAttention
Definition device_backend.h:107
@ NormPartials
Definition device_backend.h:105
@ Bf16ToFp32
Definition device_backend.h:102
@ GradientPartials
Definition device_backend.h:106
@ SharedScratch
Definition device_backend.h:99
@ Bf16Gradient
Definition device_backend.h:101
@ Count
Definition device_backend.h:108
@ Int8Dequant
Definition device_backend.h:103
@ Bf16Input
Definition device_backend.h:100
@ PoolingMask
Definition device_backend.h:104
void reset_last_error() noexcept
CopyKind
Definition device_backend.h:65
@ HostToHost
Definition device_backend.h:66
@ DeviceToHost
Definition device_backend.h:68
@ HostToDevice
Definition device_backend.h:67
@ DeviceToDevice
Definition device_backend.h:69
constexpr bool is_cuda_build() noexcept
Definition device_backend.h:72
int64_t conv_workspace_limit_bytes() noexcept
constexpr std::array< const char *, static_cast< size_t >(GraphWorkspaceKind::Count)> graph_workspace_labels
Definition device_backend.h:112
MaxPoolingRung
Definition device_backend.h:168
@ Cudnn
Definition device_backend.h:168
void check_last_error()
DnnOpTensorDescriptor get_op_tensor_add_descriptor()
int lanes_available() noexcept
void synchronize(DeviceStream=nullptr)
BlasHandle get_cublas_handle()
void set_conv_workspace_auto_limit_bytes(int64_t) noexcept
void launch_graph(const GraphExecHandle &, DeviceStream)
BatchNormBackwardRung
Definition device_backend.h:166
@ Auto
Definition device_backend.h:166
@ PlainNative
Definition device_backend.h:166
@ StagedFp32
Definition device_backend.h:166
@ OwnKernel
Definition device_backend.h:166
Definition configuration.h:10
bfloat16 * ensure_bf16_gradient_workspace(Index n)
Definition device_backend.h:379
void release_thread_workspaces()
cudaDataType_t DeviceDataType
Definition opennn_types.h:168
void set_threads_number(int)
cudaGraphExec_t DeviceGraphExec
Definition opennn_types.h:138
cublasLtHandle_t BlasLtHandle
Definition opennn_types.h:140
void * ensure_shared_scratch(size_t bytes)
Definition device_backend.h:382
Device
Definition configuration.h:12
float * ensure_bf16_to_fp32_workspace(Index n)
Definition device_backend.h:381
cudnnStatus_t DnnStatus
Definition opennn_types.h:145
cudnnHandle_t DnnHandle
Definition opennn_types.h:141
cudnnOpTensorDescriptor_t DnnOpTensorDescriptor
Definition opennn_types.h:142
ThreadPoolDevice & get_device()
void run_lt_matmul_cached(int, int, int, BlasOperation transA, BlasOperation transB, LinearEpilogue epilogue, const void *, const void *, void *, const void *, DeviceDataType dtype_a=CUDA_R_32F, DeviceDataType dtype_b=CUDA_R_32F, DeviceDataType out_dtype=CUDA_R_32F, const void *aux_pointer=nullptr, const void *addend=nullptr, float alpha=1.0f, float beta=0.0f, int lda=0, int ldb=0, int ldd=0)
const void * bias_for_gemm_bf16(const TensorView &)
void gemm_strided_batched_cuda(BlasOperation transa, BlasOperation transb, int, int, int, const void *, DeviceDataType Atype, int, long long stride_a, const void *, DeviceDataType Btype, int, long long stride_b, void *, DeviceDataType Ctype, int, long long stride_c, int, float alpha=1.0f, float beta=0.0f)
LinearEpilogue
Definition configuration.h:42
Type
Definition configuration.h:13
const void * data_for_gemm_dtype(const TensorView &, Type)
cudaEvent_t DeviceEvent
Definition opennn_types.h:136
void * ensure_workspace_bytes(device::GraphWorkspaceKind, Index bytes)
cublasMath_t BlasMathMode
Definition opennn_types.h:162
cudaStream_t DeviceStream
Definition opennn_types.h:135
cublasHandle_t BlasHandle
Definition opennn_types.h:139
bfloat16 * ensure_int8_dequant_workspace(Index n)
Definition device_backend.h:380
cublasOperation_t BlasOperation
Definition opennn_types.h:167
__nv_bfloat16 bfloat16
Definition opennn_types.h:171
cublasPointerMode_t BlasPointerMode
Definition opennn_types.h:161
T * ensure_workspace(device::GraphWorkspaceKind kind, Index count)
Definition device_backend.h:375
float * ensure_flash_attention_workspace(Index n)
Definition device_backend.h:383
DnnStatus(* deleter)(Handle)
Definition device_backend.h:20
CudnnDescriptor & operator=(CudnnDescriptor &&other) noexcept
Definition device_backend.h:31
~CudnnDescriptor()
Definition device_backend.h:45
Handle get() const noexcept
Definition device_backend.h:54
Handle handle
Definition device_backend.h:18
CudnnDescriptor & operator=(const CudnnDescriptor &)=delete
void reset()
Definition device_backend.h:47
CudnnDescriptor(const CudnnDescriptor &)=delete
CudnnDescriptor(CudnnDescriptor &&other) noexcept
Definition device_backend.h:27
Definition tensor_types.h:540
Definition device_backend.h:324
void operator()(DeviceGraphExec) const noexcept
Definition device_backend.h:117
void * data
Definition device_backend.h:118
Index bytes
Definition device_backend.h:119