The Gaudi Framework
master (57817a18)
Toggle main menu visibility
Loading...
Searching...
No Matches
CUDADeviceArray.cpp
Go to the documentation of this file.
1
/***********************************************************************************\
2
* (c) Copyright 2024-2026 CERN for the benefit of the LHCb and ATLAS collaborations *
3
* *
4
* This software is distributed under the terms of the Apache version 2 licence, *
5
* copied verbatim in the file "LICENSE". *
6
* *
7
* In applying this licence, CERN does not waive the privileges and immunities *
8
* granted to it by virtue of its status as an Intergovernmental Organization *
9
* or submit itself to any jurisdiction. *
10
\***********************************************************************************/
11
#include "
CUDADeviceArray.h
"
12
13
// Gaudi
14
#include <
Gaudi/AsynchronousAlgorithm.h
>
15
#include <
Gaudi/CUDA/CUDAStream.h
>
16
17
// CUDA
18
#ifndef __CUDACC__
19
# include <cuda_runtime.h>
20
#endif
21
22
// Fibers
23
#include <boost/fiber/condition_variable.hpp>
24
#include <boost/fiber/mutex.hpp>
25
26
// standard library
27
#include <chrono>
28
#include <format>
29
#include <string>
30
#include <thread>
31
32
namespace
Gaudi::CUDA::Detail
{
33
using namespace
std::chrono_literals;
34
namespace
{
35
const
std::string DEVARREXC =
"CUDADeviceArrayException"
;
36
std::string err_fmt( cudaError_t err, std::string file,
int
line ) {
37
const
char
* errname = cudaGetErrorName( err );
38
const
char
* errstr = cudaGetErrorString( err );
39
std::string errmsg =
40
std::format(
"Encountered CUDA error {} [{}]: {} on {}:{}"
, errname,
int
( err ), errstr, file, line );
41
return
errmsg;
42
}
43
44
boost::fibers::mutex gpu_mem_mtx;
45
boost::fibers::condition_variable gpu_mem_cv;
46
}
// namespace
47
48
void
*
allocateWithStream
( std::size_t size,
Stream
& stream ) {
49
const
Gaudi::AsynchronousAlgorithm
* parent = stream.asyncParent();
50
void
* devPtr =
nullptr
;
51
cudaError_t err = cudaSuccess;
52
do
{
53
err = cudaMallocAsync( &devPtr, size, stream );
54
if
( err == cudaSuccess ) {
break
; }
55
if
( err == cudaErrorMemoryAllocation && parent !=
nullptr
) {
56
// Waiting and retrying only works if we're in an asynchronous algorithm
57
cudaGetLastError();
58
parent
59
->
decorateSuspension
( [&]() {
60
std::unique_lock lck( gpu_mem_mtx );
61
gpu_mem_cv.wait( lck );
62
return
StatusCode::SUCCESS
;
63
} )
64
.orThrow(
"Error suspending while waiting for memory"
, DEVARREXC );
65
}
else
{
66
throw
GaudiException
( err_fmt( err, __FILE__, __LINE__ ), DEVARREXC,
StatusCode::FAILURE
);
67
}
68
}
while
( err == cudaErrorMemoryAllocation );
69
return
devPtr;
70
}
71
72
void
*
allocateNoStream
( std::size_t size,
Gaudi::AsynchronousAlgorithm
* parent ) {
73
void
* devPtr =
nullptr
;
74
cudaError_t err = cudaSuccess;
75
do
{
76
err = cudaMalloc( &devPtr, size );
77
if
( err == cudaSuccess ) {
break
; }
78
if
( err == cudaErrorMemoryAllocation ) {
79
cudaGetLastError();
80
// If called from an AsynchronousAlgorithm, wait as in the with stream variant
81
// Otherwise, the thread should sleep
82
if
( parent !=
nullptr
) {
83
parent
84
->
decorateSuspension
( [&]() {
85
std::unique_lock lck( gpu_mem_mtx );
86
gpu_mem_cv.wait( lck );
87
return
StatusCode::SUCCESS
;
88
} )
89
.orThrow(
"Error supending while waiting for memory"
, DEVARREXC );
90
}
else
{
91
std::this_thread::sleep_for( 100ms );
92
}
93
}
else
{
94
throw
GaudiException
( err_fmt( err, __FILE__, __LINE__ ), DEVARREXC,
StatusCode::FAILURE
);
95
}
96
}
while
( err == cudaErrorMemoryAllocation );
97
return
devPtr;
98
}
99
100
void
freeWithStream
(
void
* ptr,
Stream
& stream ) {
101
cudaError_t err = cudaFreeAsync( ptr, stream );
102
if
( err != cudaSuccess ) {
103
throw
GaudiException
( err_fmt( err, __FILE__, __LINE__ ), DEVARREXC,
StatusCode::FAILURE
);
104
}
105
gpu_mem_cv.notify_all();
106
}
107
108
void
freeNoStream
(
void
* ptr ) {
109
cudaError_t err = cudaFree( ptr );
110
if
( err != cudaSuccess ) {
111
throw
GaudiException
( err_fmt( err, __FILE__, __LINE__ ), DEVARREXC,
StatusCode::FAILURE
);
112
}
113
gpu_mem_cv.notify_all();
114
}
115
116
void
copyHostToDeviceWithStream
(
void
* devPtr,
const
void
* hstPtr, std::size_t size,
Stream
& stream ) {
117
cudaError_t err = cudaMemcpyAsync( devPtr, hstPtr, size, cudaMemcpyHostToDevice, stream );
118
if
( err != cudaSuccess ) {
119
throw
GaudiException
( err_fmt( err, __FILE__, __LINE__ ), DEVARREXC,
StatusCode::FAILURE
);
120
}
121
// await stream to avoid deleting host memory before copy is done
122
stream.await().orThrow(
"Await error"
, DEVARREXC );
123
}
124
125
void
copyHostToDeviceNoStream
(
void
* devPtr,
const
void
* hstPtr, std::size_t size ) {
126
cudaError_t err = cudaMemcpy( devPtr, hstPtr, size, cudaMemcpyHostToDevice );
127
if
( err != cudaSuccess ) {
128
throw
GaudiException
( err_fmt( err, __FILE__, __LINE__ ), DEVARREXC,
StatusCode::FAILURE
);
129
}
130
}
131
132
void
copyDeviceToHostWithStream
(
void
* hstPtr,
const
void
* devPtr, std::size_t size,
Stream
& stream ) {
133
cudaError_t err = cudaMemcpyAsync( hstPtr, devPtr, size, cudaMemcpyDeviceToHost, stream );
134
if
( err != cudaSuccess ) {
135
throw
GaudiException
( err_fmt( err, __FILE__, __LINE__ ), DEVARREXC,
StatusCode::FAILURE
);
136
}
137
// await stream to avoid deleting host memory before copy is done
138
stream.await().orThrow(
"Await error"
, DEVARREXC );
139
}
140
141
void
copyDeviceToHostNoStream
(
void
* hstPtr,
const
void
* devPtr, std::size_t size ) {
142
cudaError_t err = cudaMemcpy( hstPtr, devPtr, size, cudaMemcpyDeviceToHost );
143
if
( err != cudaSuccess ) {
144
throw
GaudiException
( err_fmt( err, __FILE__, __LINE__ ), DEVARREXC,
StatusCode::FAILURE
);
145
}
146
}
147
148
void
copyDeviceToDeviceWithStream
(
void
* destDevPtr,
const
void
* srcDevPtr, std::size_t size,
Stream
& stream ) {
149
cudaError_t err = cudaMemcpyAsync( destDevPtr, srcDevPtr, size, cudaMemcpyDeviceToDevice, stream );
150
if
( err != cudaSuccess ) {
151
throw
GaudiException
( err_fmt( err, __FILE__, __LINE__ ), DEVARREXC,
StatusCode::FAILURE
);
152
}
153
}
154
155
void
copyDeviceToDeviceNoStream
(
void
* destDevPtr,
const
void
* srcDevPtr, std::size_t size ) {
156
cudaError_t err = cudaMemcpy( destDevPtr, srcDevPtr, size, cudaMemcpyDeviceToDevice );
157
if
( err != cudaSuccess ) {
158
throw
GaudiException
( err_fmt( err, __FILE__, __LINE__ ), DEVARREXC,
StatusCode::FAILURE
);
159
}
160
}
161
}
// namespace Gaudi::CUDA::Detail
AsynchronousAlgorithm.h
CUDADeviceArray.h
CUDAStream.h
Gaudi::AsynchronousAlgorithm
Base class for asynchronous algorithms.
Definition
AsynchronousAlgorithm.h:33
Gaudi::AsynchronousAlgorithm::decorateSuspension
StatusCode decorateSuspension(std::function< StatusCode()> f) const
Decorate a direct call to a suspending (or possibly suspending) function with the necessary pre- and ...
Definition
AsynchronousAlgorithm.cpp:75
Gaudi::CUDA::Stream
Definition
CUDAStream.h:20
GaudiException
Define general base for Gaudi exception.
Definition
GaudiException.h:29
StatusCode::SUCCESS
constexpr static const auto SUCCESS
Definition
StatusCode.h:99
StatusCode::FAILURE
constexpr static const auto FAILURE
Definition
StatusCode.h:100
Gaudi::CUDA::Detail
Definition
CUDADeviceArray.cpp:32
Gaudi::CUDA::Detail::copyDeviceToDeviceNoStream
void copyDeviceToDeviceNoStream(void *destDevPtr, const void *srcDevPtr, std::size_t size)
Definition
CUDADeviceArray.cpp:155
Gaudi::CUDA::Detail::allocateNoStream
void * allocateNoStream(std::size_t size, Gaudi::AsynchronousAlgorithm *parent)
Definition
CUDADeviceArray.cpp:72
Gaudi::CUDA::Detail::copyDeviceToHostWithStream
void copyDeviceToHostWithStream(void *hstPtr, const void *devPtr, std::size_t size, Stream &stream)
Definition
CUDADeviceArray.cpp:132
Gaudi::CUDA::Detail::copyHostToDeviceNoStream
void copyHostToDeviceNoStream(void *devPtr, const void *hstPtr, std::size_t size)
Definition
CUDADeviceArray.cpp:125
Gaudi::CUDA::Detail::allocateWithStream
void * allocateWithStream(std::size_t size, Stream &stream)
Definition
CUDADeviceArray.cpp:48
Gaudi::CUDA::Detail::copyDeviceToHostNoStream
void copyDeviceToHostNoStream(void *hstPtr, const void *devPtr, std::size_t size)
Definition
CUDADeviceArray.cpp:141
Gaudi::CUDA::Detail::copyDeviceToDeviceWithStream
void copyDeviceToDeviceWithStream(void *destDevPtr, const void *srcDevPtr, std::size_t size, Stream &stream)
Definition
CUDADeviceArray.cpp:148
Gaudi::CUDA::Detail::freeNoStream
void freeNoStream(void *ptr)
Definition
CUDADeviceArray.cpp:108
Gaudi::CUDA::Detail::copyHostToDeviceWithStream
void copyHostToDeviceWithStream(void *devPtr, const void *hstPtr, std::size_t size, Stream &stream)
Definition
CUDADeviceArray.cpp:116
Gaudi::CUDA::Detail::freeWithStream
void freeWithStream(void *ptr, Stream &stream)
Definition
CUDADeviceArray.cpp:100
GaudiCUDA
src
CUDADeviceArray.cpp
Generated on
for The Gaudi Framework by
1.17.0