16#include <sys/resource.h>
18#include <tbb/tick_count.h>
24#define ON_DEBUG if ( msgLevel( MSG::DEBUG ) )
25#define DEBUG_MSG ON_DEBUG debug()
27#define ON_VERBOSE if ( msgLevel( MSG::VERBOSE ) )
28#define VERBOSE_MSG ON_VERBOSE verbose()
34 : AsynchronousAlgorithm(
name, pSvc ) {
38 CHM::accessor name_ninstances;
40 name_ninstances->second += 1;
84 std::vector<double> input{};
97 auto getGausRandom = [](
double mean,
double sigma ) ->
double {
98 unsigned int seed = std::clock();
100 auto getUnifRandom = [](
unsigned int& seed ) ->
double {
102 constexpr unsigned int m = 232;
103 constexpr unsigned int a = 1664525;
104 constexpr unsigned int c = 1013904223;
105 seed = ( a * seed + c ) % m;
106 const double unif = double( seed ) / m;
112 unif1 = getUnifRandom( seed );
113 unif2 = getUnifRandom( seed );
114 }
while ( unif1 < std::numeric_limits<double>::epsilon() );
116 const double normal = sqrt( -2. * log( unif1 ) ) * cos( 2 * M_PI * unif2 );
118 return normal * sigma + mean;
123 input.reserve( 50000 * crunchtime );
124 for (
int i = 0; i < 50000 * crunchtime; ++i ) { input.push_back( getGausRandom( 20.0, 1.0 ) ); }
125 unsigned int crunchtime_ms = 1000 * crunchtime;
128 double lower_bound = std::ranges::min( input );
129 double upper_bound = std::ranges::max( input ) * 256;
130 DEBUG_MSG <<
"Crunching time will be: " << crunchtime_ms <<
" ms" <<
endmsg;
131 DEBUG_MSG <<
"Start event " << ctx.evt() <<
" in slot " << ctx.slot() <<
" on pthreadID " << std::hex
132 << pthread_self() << std::dec <<
endmsg;
135 tbb::tick_count starttbb = tbb::tick_count::now();
139 if ( !inputHandle->isValid() )
continue;
144 obj = inputHandle->get();
146 error() <<
"Caught exception with message " << e.
what() <<
" in evt " << ctx.evt() <<
endmsg;
149 if ( obj ==
nullptr )
error() <<
"A read object was a null pointer." <<
endmsg;
153 auto startcrunch = std::chrono::steady_clock::now();
154 std::vector<double> out{};
155 gpuExecute( input, out ).orThrow(
"GPU_EXECUTE" );
156 auto endcrunch = std::chrono::steady_clock::now();
157 int total_entries = std::accumulate( out.begin() + 2, out.end(), 0, std::plus{} );
159 ( out.at( 0 ) == lower_bound ) && ( out.at( 1 ) == upper_bound ) && ( total_entries == 256 * input.size() );
163 "GPU Crunch time: {} s. Input length {}, total entries {}. Pass: Lower {}, Upper {}, Entries {} ({} "
165 std::chrono::duration_cast<std::chrono::milliseconds>( endcrunch - startcrunch ).count() / 1
e3,
166 input.size(), total_entries, out.at( 0 ) == lower_bound, out.at( 1 ) == upper_bound,
167 total_entries == 256 * input.size(), 256 * input.size() - total_entries )
172 if ( !outputHandle->isValid() )
continue;
176 outputHandle->put( std::make_unique<DataObject>() );
178 error() <<
"Caught exception with message " << e.
what() <<
" in evt " << ctx.evt() <<
endmsg;
183 tbb::tick_count endtbb = tbb::tick_count::now();
184 const double actualRuntime = ( endtbb - starttbb ).seconds();
186 DEBUG_MSG <<
"Finish event " << ctx.evt() <<
" in " << int( 1000 * actualRuntime ) <<
" ms" <<
endmsg;
188 DEBUG_MSG <<
"Timing: ExpectedCrunchtime= " << crunchtime_ms
189 <<
" ms. ActualTotalRuntime= " << int( 1000 * actualRuntime )
190 <<
" ms. Ratio= " << crunchtime / actualRuntime <<
endmsg;
201 unsigned int ninstances;
204 CHM::const_accessor const_name_ninstances;
206 ninstances = const_name_ninstances->second;
209 constexpr double s2ms = 1000.;
211 if ( ninstances != 0 ) {
212 info() <<
"Summary: name= " <<
name() <<
"\t avg_runtime= " <<
m_avg_runtime * s2ms <<
"\t n_clones= " << ninstances
215 CHM::accessor name_ninstances;
217 name_ninstances->second = 0;
HepRndm::Engine< DRand48Engine > e3
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
#define DECLARE_COMPONENT(type)
MsgStream & error() const
shortcut for the method msgStream(MSG::ERROR)
MsgStream & warning() const
shortcut for the method msgStream(MSG::WARNING)
const SmartIF< IMessageSvc > & msgSvc() const
The standard message service.
MsgStream & info() const
shortcut for the method msgStream(MSG::INFO)
DataObjectHandle.h GaudiKernel/DataObjectHandle.h.
A DataObject is the base class of any identifiable object on any data store.
This class represents an entry point to all the event specific data.
A test asynchronous algorithm on the GPU.
GPUCruncher()
the default constructor is disabled
StatusCode finalize() override
the finalization of the algorithm
StatusCode gpuExecute(const std::vector< double > &in, std::vector< double > &out) const
The GPU intensive function.
std::vector< DataObjectHandle< DataObject > * > m_inputHandles
static CHM m_name_ncopies_map
Gaudi::Property< double > m_var_runtime
Gaudi::Property< double > m_avg_runtime
tbb::concurrent_hash_map< std::string, unsigned int > CHM
virtual ~GPUCruncher()
virtual & protected desctrustor
StatusCode execute(const EventContext &ctx) const override
the execution of the algorithm
Gaudi::Property< std::vector< std::string > > m_inpKeys
std::vector< DataObjectHandle< DataObject > * > m_outputHandles
StatusCode initialize() override
Its initialization.
Gaudi::Property< std::vector< std::string > > m_outKeys
Gaudi::Details::PropertyBase * declareProperty(const std::string &name, ToolHandle< T > &hndl, const std::string &doc="none")
StatusCode initialize() override
the default (empty) implementation of IStateful::initialize() method
StatusCode finalize() override
the default (empty) implementation of IStateful::finalize() method
const std::string & name() const override
The identifying name of the algorithm object.
Define general base for Gaudi exception.
const char * what() const override
method from std::exception
The ISvcLocator is the interface implemented by the Service Factory in the Application Manager to loc...
Definition of the MsgStream class used to transmit messages.
This class is used for returning status codes from appropriate routines.
constexpr static const auto SUCCESS