Loading [MathJax]/extensions/tex2jax.js
The Gaudi Framework  v31r0 (aeb156f0)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
AlgResourcePool.cpp
Go to the documentation of this file.
1 #include "AlgResourcePool.h"
4 
5 // C++
6 #include <functional>
7 #include <queue>
8 
9 // DP TODO: Manage smartifs and not pointers to algos
10 
11 // Instantiation of a static factory class used by clients to create instances of this service
13 
14 #define ON_DEBUG if ( msgLevel( MSG::DEBUG ) )
15 #define DEBUG_MSG ON_DEBUG debug()
16 
17 //---------------------------------------------------------------------------
18 
19 // destructor
21  for ( auto& algoId_algoQueue : m_algqueue_map ) {
22  auto* queue = algoId_algoQueue.second;
23  delete queue;
24  }
25 }
26 
27 //---------------------------------------------------------------------------
28 
29 // initialize the pool with the list of algos known to the IAlgManager
31 
33  if ( !sc.isSuccess() ) warning() << "Base class could not be started" << endmsg;
34 
35  // Try to recover the topAlgList from the ApplicationManager for backward-compatibility
36  if ( m_topAlgNames.value().empty() ) {
37  info() << "TopAlg list empty. Recovering the one of Application Manager" << endmsg;
38  const Gaudi::Utils::TypeNameString appMgrName( "ApplicationMgr/ApplicationMgr" );
39  SmartIF<IProperty> appMgrProps( serviceLocator()->service( appMgrName ) );
40  m_topAlgNames.assign( appMgrProps->getProperty( "TopAlg" ) );
41  }
42 
43  sc = decodeTopAlgs();
44  if ( sc.isFailure() ) warning() << "Algorithms could not be properly decoded." << endmsg;
45 
46  // let's assume all resources are there
48  return StatusCode::SUCCESS;
49 }
50 
51 //---------------------------------------------------------------------------
52 
54 
55  StatusCode startSc = Service::start();
56  if ( !startSc.isSuccess() ) return startSc;
57 
58  // sys-Start the algos
59  for ( auto& ialgo : m_algList ) {
60  startSc = ialgo->sysStart();
61  if ( startSc.isFailure() ) {
62  error() << "Unable to start Algorithm: " << ialgo->name() << endmsg;
63  return startSc;
64  }
65  }
66  return StatusCode::SUCCESS;
67 }
68 
69 //---------------------------------------------------------------------------
70 
72 
73  std::hash<std::string> hash_function;
74  size_t algo_id = hash_function( name );
75  auto itQueueIAlgPtr = m_algqueue_map.find( algo_id );
76 
77  if ( itQueueIAlgPtr == m_algqueue_map.end() ) {
78  error() << "Algorithm " << name << " requested, but not recognised" << endmsg;
79  algo = nullptr;
80  return StatusCode::FAILURE;
81  }
82 
83  StatusCode sc;
84  if ( blocking ) {
85  itQueueIAlgPtr->second->pop( algo );
86  } else {
87  if ( !itQueueIAlgPtr->second->try_pop( algo ) ) { sc = StatusCode::FAILURE; }
88  }
89 
90  // Note that reentrant algos are not consumed so we put them
91  // back immediately in the queue at the end of this function.
92  // Now we may still be called again in between and get this
93  // error. In such a case, the Scheduler will retry later.
94  // This is of course not optimal, but should only happen very
95  // seldom and thud won't affect the global efficiency
96  if ( sc.isFailure() )
97  DEBUG_MSG << "No instance of algorithm " << name << " could be retrieved in non-blocking mode" << endmsg;
98 
99  // if (m_lazyCreation ) {
100  // TODO: fill the lazyCreation part
101  // }
102  if ( sc.isSuccess() ) {
103  state_type requirements = m_resource_requirements[algo_id];
105  if ( requirements.is_subset_of( m_available_resources ) ) {
106  m_available_resources ^= requirements;
107  } else {
108  sc = StatusCode::FAILURE;
109  error() << "Failure to allocate resources of algorithm " << name << endmsg;
110  // in case of not reentrant, push it back. Reentrant ones are pushed back
111  // in all cases further down
112  if ( 0 != algo->cardinality() ) { itQueueIAlgPtr->second->push( algo ); }
113  }
115  if ( 0 == algo->cardinality() ) {
116  // push back reentrant algos immediately as it can be reused
117  itQueueIAlgPtr->second->push( algo );
118  }
119  }
120  return sc;
121 }
122 
123 //---------------------------------------------------------------------------
124 
126 
127  std::hash<std::string> hash_function;
128  size_t algo_id = hash_function( name );
129 
130  // release resources used by the algorithm
134 
135  // release algorithm itself if not reentrant
136  if ( 0 != algo->cardinality() ) { m_algqueue_map[algo_id]->push( algo ); }
137  return StatusCode::SUCCESS;
138 }
139 
140 //---------------------------------------------------------------------------
141 
146  return StatusCode::SUCCESS;
147 }
148 
149 //---------------------------------------------------------------------------
150 
155  return StatusCode::SUCCESS;
156 }
157 
158 //---------------------------------------------------------------------------
159 
160 StatusCode AlgResourcePool::flattenSequencer( Gaudi::Algorithm* algo, ListAlg& alglist, unsigned int recursionDepth ) {
161 
163 
164  if ( algo->isSequence() ) {
165  auto seq = dynamic_cast<Gaudi::Sequence*>( algo );
166  if ( seq == 0 ) {
167  error() << "Unable to dcast Algorithm " << algo->name() << " to a Sequence, but it has isSequence==true"
168  << endmsg;
169  return StatusCode::FAILURE;
170  }
171 
172  auto subAlgorithms = seq->subAlgorithms();
173 
174  // Recursively unroll
175  ++recursionDepth;
176 
177  for ( auto subalgo : *subAlgorithms ) {
178  sc = flattenSequencer( subalgo, alglist, recursionDepth );
179  if ( sc.isFailure() ) {
180  error() << "Algorithm " << subalgo->name() << " could not be flattened" << endmsg;
181  return sc;
182  }
183  }
184  } else {
185  alglist.emplace_back( algo );
186  return sc;
187  }
188  return sc;
189 }
190 
191 //---------------------------------------------------------------------------
192 
194 
196  if ( !algMan.isValid() ) {
197  error() << "Algorithm manager could not be properly fetched." << endmsg;
198  return StatusCode::FAILURE;
199  }
200 
201  // Useful lambda not to repeat ourselves --------------------------
202  auto createAlg = [&algMan, this]( const std::string& item_type, const std::string& item_name, IAlgorithm*& algo ) {
203  StatusCode createAlgSc = algMan->createAlgorithm( item_type, item_name, algo, true, false );
204  if ( createAlgSc.isFailure() )
205  this->warning() << "Algorithm " << item_type << "/" << item_name << " could not be created." << endmsg;
206  };
207  // End of lambda --------------------------------------------------
208 
210 
211  // Fill the top alg list ----
212  const std::vector<std::string>& topAlgNames = m_topAlgNames.value();
213  for ( auto& name : topAlgNames ) {
214  IAlgorithm* algo( nullptr );
215 
217  const std::string& item_name = item.name();
218  const std::string& item_type = item.type();
219  SmartIF<IAlgorithm> algoSmartIF( algMan->algorithm( item_name, false ) );
220 
221  if ( !algoSmartIF.isValid() ) {
222  createAlg( item_type, item_name, algo );
223  algoSmartIF = algo;
224  }
225  // Init and start
226  algoSmartIF->sysInitialize().ignore();
227  m_topAlgList.push_back( algoSmartIF );
228  }
229  // Top Alg list filled ----
230 
231  // Now we unroll it ----
232  for ( auto& algoSmartIF : m_topAlgList ) {
233  Gaudi::Algorithm* algorithm = dynamic_cast<Gaudi::Algorithm*>( algoSmartIF.get() );
234  if ( !algorithm ) {
235  fatal() << "Conversion from IAlgorithm to Gaudi::Algorithm failed" << endmsg;
236  return StatusCode::FAILURE;
237  }
238  sc = flattenSequencer( algorithm, m_flatUniqueAlgList );
239  }
240  // stupid O(N^2) unique-ification..
241  for ( auto i = begin( m_flatUniqueAlgList ); i != end( m_flatUniqueAlgList ); ++i ) {
242  auto n = next( i );
243  while ( n != end( m_flatUniqueAlgList ) ) {
244  if ( *n == *i )
246  else
247  ++n;
248  }
249  }
250  if ( msgLevel( MSG::DEBUG ) ) {
251  debug() << "List of algorithms is: " << endmsg;
252  for ( auto& algo : m_flatUniqueAlgList )
253  debug() << " o " << algo->type() << "/" << algo->name() << " @ " << algo << endmsg;
254  }
255 
256  // Unrolled ---
257 
258  // Now let's manage the clones
259  unsigned int resource_counter( 0 );
260  std::hash<std::string> hash_function;
261  for ( auto& ialgoSmartIF : m_flatUniqueAlgList ) {
262 
263  const std::string& item_name = ialgoSmartIF->name();
264 
265  verbose() << "Treating resource management and clones of " << item_name << endmsg;
266 
267  Gaudi::Algorithm* algo = dynamic_cast<Gaudi::Algorithm*>( ialgoSmartIF.get() );
268  if ( !algo ) {
269  fatal() << "Conversion from IAlgorithm to Gaudi::Algorithm failed" << endmsg;
270  return StatusCode::FAILURE;
271  }
272  const std::string& item_type = algo->type();
273 
274  size_t algo_id = hash_function( item_name );
276  m_algqueue_map[algo_id] = queue;
277 
278  // DP TODO Do it properly with SmartIFs, also in the queues
279  IAlgorithm* ialgo( ialgoSmartIF.get() );
280 
281  queue->push( ialgo );
282  m_algList.push_back( ialgo );
283  if ( ialgo->isReEntrant() ) {
284  if ( ialgo->cardinality() != 0 ) {
285  info() << "Algorithm " << ialgo->name() << " is ReEntrant, but Cardinality was set to " << ialgo->cardinality()
286  << endmsg;
287  m_n_of_allowed_instances[algo_id] = ialgo->cardinality();
288  } else {
289  m_n_of_allowed_instances[algo_id] = 1;
290  }
291  } else if ( ialgo->isClonable() ) {
292  m_n_of_allowed_instances[algo_id] = ialgo->cardinality();
293  } else {
294  if ( ialgo->cardinality() == 1 ) {
295  m_n_of_allowed_instances[algo_id] = 1;
296  } else {
297  if ( !m_overrideUnClonable ) {
298  info() << "Algorithm " << ialgo->name() << " is un-Clonable but Cardinality was set to "
299  << ialgo->cardinality() << ". Only creating 1 instance" << endmsg;
300  m_n_of_allowed_instances[algo_id] = 1;
301  } else {
302  warning() << "Overriding UnClonability of Algorithm " << ialgo->name() << ". Setting Cardinality to "
303  << ialgo->cardinality() << endmsg;
304  m_n_of_allowed_instances[algo_id] = ialgo->cardinality();
305  }
306  }
307  }
308  m_n_of_created_instances[algo_id] = 1;
309 
310  state_type requirements( 0 );
311 
312  for ( auto& resource_name : ialgo->neededResources() ) {
313  auto ret = m_resource_indices.emplace( resource_name, resource_counter );
314  // insert successful means == wasn't known before. So increment counter
315  if ( ret.second ) ++resource_counter;
316  // Resize for every algo according to the found resources
317  requirements.resize( resource_counter );
318  // in any case the return value holds the proper product index
319  requirements[ret.first->second] = true;
320  }
321 
322  m_resource_requirements[algo_id] = requirements;
323 
324  // potentially create clones; if not lazy creation we have to do it now
325  if ( !m_lazyCreation ) {
326  for ( unsigned int i = 1, end = m_n_of_allowed_instances[algo_id]; i < end; ++i ) {
327  debug() << "type/name to create clone of: " << item_type << "/" << item_name << endmsg;
328  IAlgorithm* ialgoClone( nullptr );
329  createAlg( item_type, item_name, ialgoClone );
330  ialgoClone->setIndex( i );
331  if ( ialgoClone->sysInitialize().isFailure() ) {
332  error() << "unable to initialize Algorithm clone " << ialgoClone->name() << endmsg;
333  sc = StatusCode::FAILURE;
334  // FIXME: should we delete this failed clone?
335  } else {
336  queue->push( ialgoClone );
337  m_n_of_created_instances[algo_id] += 1;
338  }
339  }
340  }
341  }
342 
343  // Now resize all the requirement bitsets to the same size
344  for ( auto& kv : m_resource_requirements ) { kv.second.resize( resource_counter ); }
345 
346  // Set all resources to be available
347  m_available_resources.resize( resource_counter );
348  m_available_resources.set();
349 
350  return sc;
351 }
352 
353 //---------------------------------------------------------------------------
354 
357  for ( auto algoSmartIF : m_flatUniqueAlgList ) m_flatUniqueAlgPtrList.push_back( algoSmartIF.get() );
358  return m_flatUniqueAlgPtrList;
359 }
360 
361 //---------------------------------------------------------------------------
362 
365  for ( auto algoSmartIF : m_topAlgList ) m_topAlgPtrList.push_back( algoSmartIF.get() );
366  return m_topAlgPtrList;
367 }
368 
369 //---------------------------------------------------------------------------
370 
372 
373  StatusCode stopSc = Service::stop();
374  if ( !stopSc.isSuccess() ) return stopSc;
375 
376  // sys-Stop the algos
377  for ( auto& ialgo : m_algList ) {
378  stopSc = ialgo->sysStop();
379  if ( stopSc.isFailure() ) {
380  error() << "Unable to stop Algorithm: " << ialgo->name() << endmsg;
381  return stopSc;
382  }
383  }
384  return StatusCode::SUCCESS;
385 }
ListAlg m_flatUniqueAlgList
The flat list of algorithms w/o clones.
virtual SmartIF< IAlgorithm > & algorithm(const Gaudi::Utils::TypeNameString &typeName, const bool createIf=true)=0
Returns a smart pointer to a service.
StatusCode initialize() override
Definition: Service.cpp:60
T unlock(T...args)
const std::string & name() const override
Retrieve name of the service.
Definition: Service.cpp:274
MsgStream & info() const
shortcut for the method msgStream(MSG::INFO)
StatusCode start() override
Definition: Service.cpp:129
const std::string & name() const override
The identifying name of the algorithm object.
Definition: Algorithm.cpp:635
std::map< std::string, unsigned int > m_resource_indices
bool isSuccess() const
Definition: StatusCode.h:267
bool isSequence() const override
Are we a Sequence?
Definition: Algorithm.h:208
MsgStream & verbose() const
shortcut for the method msgStream(MSG::VERBOSE)
constexpr static const auto SUCCESS
Definition: StatusCode.h:85
std::mutex m_resource_mutex
StatusCode stop() override
T end(T...args)
virtual StatusCode getProperty(Gaudi::Details::PropertyBase *p) const =0
Get the property by property.
The AlgResourcePool is a concrete implementation of the IAlgResourcePool interface.
bool isFailure() const
Definition: StatusCode.h:130
state_type m_available_resources
Gaudi::Property< bool > m_overrideUnClonable
virtual StatusCode sysInitialize()=0
Initialization method invoked by the framework.
STL class.
#define DECLARE_COMPONENT(type)
boost::dynamic_bitset state_type
T push_back(T...args)
MsgStream & error() const
shortcut for the method msgStream(MSG::ERROR)
Helper class to parse a string of format "type/name".
MsgStream & warning() const
shortcut for the method msgStream(MSG::WARNING)
tbb::concurrent_bounded_queue< IAlgorithm * > concurrentQueueIAlgPtr
std::list< IAlgorithm * > m_flatUniqueAlgPtrList
The flat list of algorithms w/o clones which is returned.
This class is used for returning status codes from appropriate routines.
Definition: StatusCode.h:50
std::map< size_t, state_type > m_resource_requirements
T erase(T...args)
StatusCode start() override
T lock(T...args)
~AlgResourcePool() override
std::list< IAlgorithm * > m_topAlgPtrList
The top list of algorithms.
virtual unsigned int cardinality() const =0
Cardinality (Maximum number of clones that can exist) special value 0 means that algorithm is reentra...
virtual void setIndex(const unsigned int &idx)=0
Set instantiation index of Alg.
std::list< IAlgorithm * > getFlatAlgList() override
StatusCode releaseResource(const std::string &name) override
Release a certrain resource.
Gaudi::Property< std::vector< std::string > > m_topAlgNames
std::list< IAlgorithm * > getTopAlgList() override
StatusCode stop() override
Definition: Service.cpp:123
T clear(T...args)
The IAlgorithm is the interface implemented by the Algorithm base class.
Definition: IAlgorithm.h:28
StatusCode acquireResource(const std::string &name) override
Acquire a certain resource.
std::map< size_t, concurrentQueueIAlgPtr * > m_algqueue_map
const std::string & type() const override
The type of the algorithm object.
Definition: Algorithm.h:167
T find(T...args)
StatusCode decodeTopAlgs()
Decode the top alg list.
MsgStream & debug() const
shortcut for the method msgStream(MSG::DEBUG)
StatusCode flattenSequencer(Gaudi::Algorithm *sequencer, ListAlg &alglist, unsigned int recursionDepth=0)
Recursively flatten an algList.
bool isValid() const
Allow for check if smart pointer is valid.
Definition: SmartIF.h:62
const std::string & type() const
const StatusCode & ignore() const
Ignore/check StatusCode.
Definition: StatusCode.h:153
Base class from which all concrete algorithm classes should be derived.
Definition: Algorithm.h:79
T emplace(T...args)
virtual StatusCode createAlgorithm(const std::string &algtype, const std::string &algname, IAlgorithm *&alg, bool managed=false, bool checkIfExists=true )=0
Create an instance of a algorithm type that has been declared beforehand and assigns to it a name...
StatusCode acquireAlgorithm(const std::string &name, IAlgorithm *&algo, bool blocking=false) override
Acquire a certain algorithm using its name.
constexpr static const auto FAILURE
Definition: StatusCode.h:86
StatusCode service(const std::string &name, const T *&psvc, bool createIf=true) const
Access a service by name, creating it if it doesn&#39;t already exist.
Definition: Service.h:83
std::map< size_t, unsigned int > m_n_of_created_instances
#define DEBUG_MSG
AttribStringParser::Iterator begin(const AttribStringParser &parser)
const std::string & name() const
StatusCode initialize() override
MsgStream & fatal() const
shortcut for the method msgStream(MSG::FATAL)
ListAlg m_topAlgList
The list of top algorithms.
SmartIF< ISvcLocator > & serviceLocator() const override
Retrieve pointer to service locator.
Definition: Service.cpp:277
std::map< size_t, size_t > m_n_of_allowed_instances
ListAlg m_algList
The list of all algorithms created withing the Pool which are not top.
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition: MsgStream.h:192
StatusCode releaseAlgorithm(const std::string &name, IAlgorithm *&algo) override
Release a certain algorithm.
Gaudi::Property< bool > m_lazyCreation
MSG::Level msgLevel() const
get the cached level (originally extracted from the embedded MsgStream)
T emplace_back(T...args)