The Gaudi Framework  master (bb95dfce)
Loading...
Searching...
No Matches
CUDAStream.cpp
Go to the documentation of this file.
1/***********************************************************************************\
2* (c) Copyright 2023-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
12// Gaudi
15
16// CUDA
17#ifndef __CUDACC__
18# include <cuda_runtime.h>
19#endif
20
21// Others
22#include <boost/fiber/cuda/waitfor.hpp>
23#include <boost/fiber/mutex.hpp>
24#include <boost/fiber/recursive_mutex.hpp>
25
26// Standard Library
27#include <cstdio>
28#include <deque>
29#include <format>
30#include <mutex>
31#include <string>
32
33namespace Gaudi::CUDA {
34 namespace {
35 class StreamList {
36 using Mutex_t = std::recursive_mutex;
37 using Stream_t = cudaStream_t;
38
39 private:
40 std::deque<Stream_t> queue;
41 Mutex_t queue_mtx;
42
43 public:
45 void push( const Stream_t& s ) {
46 std::unique_lock lck( queue_mtx );
47 queue.push_back( s );
48 }
49
52 bool pop( Stream_t& s ) {
53 std::unique_lock lck( queue_mtx );
54 if ( queue.empty() ) { return false; }
55 s = queue.front();
56 queue.pop_front();
57 return true;
58 }
59
60 ~StreamList() {
61 Stream_t s;
62 while ( pop( s ) ) {
63 cudaStreamDestroy( s );
64 s = nullptr;
65 }
66 }
67 };
68 StreamList available_streams{};
69 std::string err_fmt( cudaError_t err, std::string file, int line ) {
70 const char* errname = cudaGetErrorName( err );
71 const char* errstr = cudaGetErrorString( err );
72 std::string errmsg =
73 std::format( "Encountered CUDA error {} [{}]: {} on {}:{}", errname, int( err ), errstr, file, line );
74 return errmsg;
75 }
76 } // namespace
77
79 : m_stream( stream )
80 , m_owning( stream == nullptr )
81 , m_parent( parent )
82 , m_async_parent( dynamic_cast<const Gaudi::AsynchronousAlgorithm*>( parent ) )
83 , m_dependents( 0 ) {}
84
86 if ( !available_streams.pop( m_stream ) ) {
87 cudaError_t err = cudaStreamCreate( &m_stream );
88 if ( err != cudaSuccess ) {
89 cudaGetLastError();
90 throw GaudiException( err_fmt( err, __FILE__, __LINE__ ), "CUDAStreamException", StatusCode::FAILURE );
91 }
92 err = cudaStreamSynchronize( m_stream );
93 if ( err != cudaSuccess ) {
94 cudaGetLastError();
95 throw GaudiException( err_fmt( err, __FILE__, __LINE__ ), "CUDAStreamException", StatusCode::FAILURE );
96 }
97 }
98 }
99
101 if ( m_dependents != 0 ) {
102 m_parent->error() << std::format( "Stream destroyed before all its dependents ({} remaining)", m_dependents )
103 << endmsg;
104 }
105 if ( await().isFailure() ) { m_parent->error() << "Error in Stream destructor" << endmsg; }
106 if ( m_owning ) { available_streams.push( m_stream ); }
107 }
108
109 Stream::operator cudaStream_t() { return m_stream; }
110
113
115 cudaError_t temp_error;
116 if ( m_async_parent != nullptr ) {
117 auto res = boost::fibers::cuda::waitfor_all( m_stream );
118 temp_error = std::get<1>( res );
119 } else {
120 temp_error = cudaStreamSynchronize( m_stream );
121 }
122 if ( ( temp_error ) != cudaSuccess ) {
123 cudaGetLastError();
124 std::string errmsg = err_fmt( temp_error, __FILE__, __LINE__ );
125 m_parent->error() << errmsg << endmsg;
126 return StatusCode::FAILURE;
127 }
128 if ( m_async_parent != nullptr ) { return m_async_parent->restoreAfterSuspend(); }
129 return StatusCode::SUCCESS;
130 }
131
134} // namespace Gaudi::CUDA
struct CUstream_st * cudaStream_t
Definition CUDAStream.h:17
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition MsgStream.h:198
Base class from which all concrete algorithm classes should be derived.
Definition Algorithm.h:87
Base class for asynchronous algorithms.
const Gaudi::AsynchronousAlgorithm * m_async_parent
Definition CUDAStream.h:25
void removeDependency()
INTERNAL: Remove a dependency.
const Gaudi::AsynchronousAlgorithm * asyncParent()
Access the parent AsynchronousAlgorithm.
void registerDependency()
INTERNAL: Register a dependency.
Stream(const Gaudi::Algorithm *parent, cudaStream_t stream)
Wrap an existing cudaStream.
const bool m_owning
Definition CUDAStream.h:23
StatusCode await()
Yield fiber until stream is done.
const Gaudi::Algorithm * parent()
Access the parent algorithm.
const Gaudi::Algorithm * m_parent
Definition CUDAStream.h:24
cudaStream_t m_stream
Definition CUDAStream.h:22
Define general base for Gaudi exception.
This class is used for returning status codes from appropriate routines.
Definition StatusCode.h:64
constexpr static const auto SUCCESS
Definition StatusCode.h:99
constexpr static const auto FAILURE
Definition StatusCode.h:100
This file provides a Grammar for the type Gaudi::Accumulators::Axis It allows to use that type from p...
Definition __init__.py:1