The Gaudi Framework  master (82fdf313)
Loading...
Searching...
No Matches
AlgContextSvc.cpp
Go to the documentation of this file.
1/***********************************************************************************\
2* (c) Copyright 1998-2024 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\***********************************************************************************/
18#include <GaudiKernel/Service.h>
20#include <boost/thread.hpp>
21#include <vector>
22
23// ============================================================================
34class AlgContextSvc : public extends<Service, IAlgContextSvc, IIncidentListener> {
35public:
37 StatusCode setCurrentAlg( IAlgorithm* a, const EventContext& context ) override;
39 StatusCode unSetCurrentAlg( IAlgorithm* a, const EventContext& context ) override;
41 IAlgorithm* currentAlg() const override;
43 const IAlgContextSvc::Algorithms& algorithms() const override {
44 if ( !m_algorithms.get() ) {
45 static IAlgContextSvc::Algorithms empty;
46 return empty;
47 }
48 return *m_algorithms;
49 }
50
51public:
52 void handle( const Incident& ) override;
53
54public:
55 StatusCode initialize() override;
56 StatusCode start() override;
57 StatusCode finalize() override;
58
59public:
60 using extends::extends;
61
62private:
64 boost::thread_specific_ptr<IAlgContextSvc::Algorithms> m_algorithms;
67
68 Gaudi::Property<bool> m_check{ this, "Check", true, "Flag to perform more checks" };
69 Gaudi::Property<bool> m_bypassInc{ this, "BypassIncidents", false,
70 "Flag to bypass begin/endevent incident requirement" };
71 std::vector<int> m_inEvtLoop;
72};
73
75
77 // Initialize the base class
79 if ( sc.isFailure() ) { return sc; }
80 // Incident Service
81 if ( m_inc ) {
82 m_inc->removeListener( this );
83 m_inc.reset();
84 }
85 // perform more checks?
87 numSlots = ( 1 > numSlots ) ? 1 : numSlots;
88 if ( numSlots > 1000 ) {
89 warning() << "Num Slots are greater than 1000. Is this correct? numSlots=" << numSlots << endmsg;
90 numSlots = 1000;
91 warning() << "Setting numSlots to " << numSlots << endmsg;
92 }
93 m_inEvtLoop.resize( numSlots, 0 );
94
95 if ( m_check ) {
96 m_inc = Service::service( "IncidentSvc", true );
97 if ( !m_inc ) {
98 error() << "Could not locate 'IncidentSvc'" << endmsg;
100 }
101 m_inc->addListener( this, IncidentType::BeginEvent );
102 m_inc->addListener( this, IncidentType::EndEvent );
103 }
104 if ( m_algorithms.get() && !m_algorithms->empty() ) {
105 warning() << "Non-empty stack of algorithms #" << m_algorithms->size() << endmsg;
106 }
107 return StatusCode::SUCCESS;
108}
109
110// implementation of start
111// needs to be removed once we have a proper service
112// for getting configuration information at initialization time
113// S. Kama
115 auto sc = Service::start();
117 numSlots = ( 1 > numSlots ) ? 1 : numSlots;
118 if ( numSlots > 1000 ) {
119 warning() << "Num Slots are greater than 1000. Is this correct? numSlots=" << numSlots << endmsg;
120 numSlots = 1000;
121 }
122 m_inEvtLoop.resize( numSlots, 0 );
123
124 return sc;
125}
126
128 if ( m_algorithms.get() && !m_algorithms->empty() ) {
129 warning() << "Non-empty stack of algorithms #" << m_algorithms->size() << endmsg;
130 }
131 // Incident Service
132 if ( m_inc ) {
133 m_inc->removeListener( this );
134 m_inc.reset();
135 }
136 // finalize the base class
137 return Service::finalize();
138}
139
141 if ( !a ) {
142 warning() << "IAlgorithm* points to NULL" << endmsg;
144 }
145 if ( !m_bypassInc ) {
146 if ( !m_inEvtLoop[context.valid() ? context.slot() : 0] ) return StatusCode::SUCCESS;
147 }
148 // check whether thread-local algorithm list already exists
149 // if not, create it
150 if ( !m_algorithms.get() ) { m_algorithms.reset( new IAlgContextSvc::Algorithms() ); }
151 if ( a->type() != "IncidentProcAlg" ) m_algorithms->push_back( a );
152
153 return StatusCode::SUCCESS;
154}
155
157 // check whether thread-local algorithm list already exists
158 // if not, create it
159 if ( !m_algorithms.get() ) { m_algorithms.reset( new IAlgContextSvc::Algorithms() ); }
160
161 if ( !a ) {
162 warning() << "IAlgorithm* points to NULL" << endmsg;
164 }
165
166 if ( !m_bypassInc ) {
167 if ( !m_inEvtLoop[context.valid() ? context.slot() : 0] ) return StatusCode::SUCCESS;
168 }
169
170 if ( a->type() != "IncidentProcAlg" ) {
171 // if ( m_algorithms->empty() || m_algorithms->back() != a ){
172 // error() << "Algorithm stack is invalid" << endmsg ;
173 // return StatusCode::FAILURE ;
174 // }
175 if ( !m_algorithms->empty() ) {
176 if ( m_algorithms->back() == a ) { m_algorithms->pop_back(); }
177 }
178 }
179 return StatusCode::SUCCESS;
180}
181
183 return ( m_algorithms.get() && !m_algorithms->empty() ) ? m_algorithms->back() : nullptr;
184}
185
186void AlgContextSvc::handle( const Incident& inc ) {
187 // some false sharing is possible but it should be negligible
188 auto currSlot = inc.context().slot();
189 if ( currSlot == EventContext::INVALID_CONTEXT_ID ) { currSlot = 0; }
190 if ( inc.type() == "BeginEvent" ) {
191 m_inEvtLoop[currSlot] = 1;
192 } else if ( inc.type() == "EndEvent" ) {
193 m_inEvtLoop[currSlot] = 0;
194 }
195
196 // This check is invalidated with RTTI AlgContext object.
197 // Whole service needs to be rewritten. Commenting the error until then
198 // to prevent test failures.
199 // if ( m_algorithms.get() && !m_algorithms->empty() ) {
200 // //skip incident processing algorithm endevent incident
201 // if((m_algorithms->size()!=1) ||
202 // (m_algorithms->back()->type()!="IncidentProcAlg")){
203 // error() << "Non-empty stack of algorithms #"
204 // << m_algorithms->size() << endmsg ;
205 // }
206 // }
207}
208
209// From here on, we have unit tests.
210#if defined( BUILD_UNIT_TESTS )
211# if __has_include( <catch2/catch.hpp>)
212// Catch2 v2
213# include <catch2/catch.hpp>
214# else
215// Catch2 v3
216# include <catch2/catch_test_macros.hpp>
217# endif
218
219# include <Gaudi/Algorithm.h>
220
221namespace mock {
222 struct ServiceLocator : implements<ISvcLocator> {
223 std::list<IService*> m_services;
224 SmartIF<IService> m_null_svc;
225
226 const std::list<IService*>& getServices() const override { return m_services; }
227 bool existsService( std::string_view /* name */ ) const override { return false; }
228 SmartIF<IService>& service( const Gaudi::Utils::TypeNameString& /* typeName */,
229 const bool /* createIf */ ) override {
230 return m_null_svc;
231 }
232 };
233 struct Algorithm : Gaudi::Algorithm {
235 StatusCode execute( const EventContext& ) const override { return StatusCode::SUCCESS; }
236 };
237} // namespace mock
238
239TEST_CASE( "AlgContextSvc basic operations" ) {
240 SmartIF<ISvcLocator> svcLoc{ new mock::ServiceLocator };
241 AlgContextSvc acs{ "AlgContextSvc", svcLoc };
242 REQUIRE( acs.setProperty( "BypassIncidents", true ).isSuccess() ); // do not try to invoke incident svc
243
244 // check that algorithms() never returns a nullptr
245 // (see https://gitlab.cern.ch/gaudi/Gaudi/-/issues/304)
246 auto empty_algorithms = &acs.algorithms();
247 REQUIRE( empty_algorithms != nullptr );
248 CHECK( empty_algorithms->empty() );
249
250 mock::Algorithm alg{ "dummy", svcLoc };
252
253 // add an algorithm
254 REQUIRE( acs.setCurrentAlg( &alg, ctx ).isSuccess() );
255 {
256 auto algorithms = &acs.algorithms();
257
258 // what we get before adding the first algorithm is a dummy static instance
259 // see https://gitlab.cern.ch/gaudi/Gaudi/-/issues/304#note_7930366
260 CHECK( empty_algorithms != algorithms );
261
262 REQUIRE( algorithms != nullptr );
263 REQUIRE( algorithms->size() == 1 );
264 CHECK( algorithms->at( 0 ) == &alg );
265 }
266
267 // removing the algorithm results in a an empty list
268 REQUIRE( acs.unSetCurrentAlg( &alg, ctx ).isSuccess() );
269 {
270 auto algorithms = &acs.algorithms();
271 REQUIRE( algorithms != nullptr );
272 REQUIRE( algorithms->empty() );
273 }
274}
275#endif
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition MsgStream.h:198
#define CHECK(x, y)
#define DECLARE_COMPONENT(type)
Simple implementation of interface IAlgContextSvc for Algorithm Context Service.
StatusCode start() override
void handle(const Incident &) override
StatusCode finalize() override
StatusCode initialize() override
StatusCode setCurrentAlg(IAlgorithm *a, const EventContext &context) override
set the currently executing algorithm ("push_back")
const IAlgContextSvc::Algorithms & algorithms() const override
get the stack of executed algorithms
Gaudi::Property< bool > m_bypassInc
SmartIF< IIncidentSvc > m_inc
pointer to Incident Service
std::vector< int > m_inEvtLoop
StatusCode unSetCurrentAlg(IAlgorithm *a, const EventContext &context) override
remove the algorithm ("pop_back")
IAlgorithm * currentAlg() const override
accessor to current algorithm:
boost::thread_specific_ptr< IAlgContextSvc::Algorithms > m_algorithms
the stack of current algorithms
Gaudi::Property< bool > m_check
MsgStream & error() const
shortcut for the method msgStream(MSG::ERROR)
MsgStream & warning() const
shortcut for the method msgStream(MSG::WARNING)
This class represents an entry point to all the event specific data.
ContextID_t slot() const
bool valid() const
static constexpr ContextID_t INVALID_CONTEXT_ID
Algorithm(std::string name, ISvcLocator *svcloc, std::string version=PACKAGE_VERSION)
Constructor.
Definition Algorithm.h:98
static GAUDI_API std::size_t numConcurrentEvents()
number of Concurrent Events (for MT)
Implementation of property with value of concrete type.
Definition PropertyFwd.h:27
std::vector< IAlgorithm * > Algorithms
the actual type of algorithm' stack
The IAlgorithm is the interface implemented by the Algorithm base class.
Definition IAlgorithm.h:36
virtual const std::string & type() const =0
The type of the algorithm.
Base class for all Incidents (computing events).
Definition Incident.h:24
EventContext context() const
Access to the EventContext of the source of the incident.
Definition Incident.h:55
const std::string & type() const
Access to the incident type.
Definition Incident.h:43
StatusCode finalize() override
Definition Service.cpp:223
SmartIF< IFace > service(const std::string &name, bool createIf=true) const
Definition Service.h:79
StatusCode start() override
Definition Service.cpp:187
StatusCode initialize() override
Definition Service.cpp:118
Small smart pointer class with automatic reference counting for IInterface.
Definition SmartIF.h:28
This class is used for returning status codes from appropriate routines.
Definition StatusCode.h:64
bool isFailure() const
Definition StatusCode.h:129
constexpr static const auto RECOVERABLE
Definition StatusCode.h:101
constexpr static const auto SUCCESS
Definition StatusCode.h:99
constexpr static const auto FAILURE
Definition StatusCode.h:100
Base class used to extend a class implementing other interfaces.
Definition extends.h:19
Base class used to implement the interfaces.
Definition implements.h:19