The Gaudi Framework  v29r0 (ff2e7097)
AlgResourcePool.cpp
Go to the documentation of this file.
1 // Include Files
2 
3 // Framework
4 #include "AlgResourcePool.h"
9 
10 // C++
11 #include <functional>
12 #include <queue>
13 
14 // DP TODO: Manage smartifs and not pointers to algos
15 
16 // Instantiation of a static factory class used by clients to create instances of this service
18 
19 #define ON_DEBUG if ( msgLevel( MSG::DEBUG ) )
20 #define DEBUG_MSG ON_DEBUG debug()
21 
22 //---------------------------------------------------------------------------
23 
24 // destructor
26 {
27 
28  for ( auto& algoId_algoQueue : m_algqueue_map ) {
29  auto* queue = algoId_algoQueue.second;
30  delete queue;
31  }
32 
33  delete m_CFGraph;
34 }
35 
36 //---------------------------------------------------------------------------
37 
38 // initialize the pool with the list of algos known to the IAlgManager
40 {
41 
43  if ( !sc.isSuccess() ) warning() << "Base class could not be started" << endmsg;
44 
45  // Try to recover the topAlgList from the ApplicationManager for backward-compatibility
46  if ( m_topAlgNames.value().empty() ) {
47  info() << "TopAlg list empty. Recovering the one of Application Manager" << endmsg;
48  const Gaudi::Utils::TypeNameString appMgrName( "ApplicationMgr/ApplicationMgr" );
49  SmartIF<IProperty> appMgrProps( serviceLocator()->service( appMgrName ) );
50  m_topAlgNames.assign( appMgrProps->getProperty( "TopAlg" ) );
51  }
52 
53  // Prepare empty control flow graph
54  // (Only ForwardScheduler requires assembling the graph in AlgResourcePool.
55  // The AvalancheScheduler relies on the graph that is assembled by the PrecedenceSvc)
56  if ( serviceLocator()->existsService( "ForwardSchedulerSvc" ) ) {
57  const std::string& name = "ControlFlowGraph";
60  }
61 
62  sc = decodeTopAlgs();
63  if ( sc.isFailure() ) warning() << "Algorithms could not be properly decoded." << endmsg;
64 
65  // let's assume all resources are there
67  return StatusCode::SUCCESS;
68 }
69 
70 //---------------------------------------------------------------------------
71 
73 {
74 
75  StatusCode startSc = Service::start();
76  if ( !startSc.isSuccess() ) return startSc;
77 
78  // sys-Start the algos
79  for ( auto& ialgo : m_algList ) {
80  startSc = ialgo->sysStart();
81  if ( startSc.isFailure() ) {
82  error() << "Unable to start Algorithm: " << ialgo->name() << endmsg;
83  return startSc;
84  }
85  }
86  return StatusCode::SUCCESS;
87 }
88 
89 //---------------------------------------------------------------------------
90 
92 {
93 
94  std::hash<std::string> hash_function;
95  size_t algo_id = hash_function( name );
96  auto itQueueIAlgPtr = m_algqueue_map.find( algo_id );
97 
98  if ( itQueueIAlgPtr == m_algqueue_map.end() ) {
99  error() << "Algorithm " << name << " requested, but not recognised" << endmsg;
100  algo = nullptr;
101  return StatusCode::FAILURE;
102  }
103 
104  StatusCode sc;
105  if ( blocking ) {
106  itQueueIAlgPtr->second->pop( algo );
107  sc = StatusCode::SUCCESS;
108  } else {
109  sc = itQueueIAlgPtr->second->try_pop( algo );
110  }
111 
112  // Note that reentrant algos are not consumed so we put them
113  // back immediately in the queue at the end of this function.
114  // Now we may still be called again in between and get this
115  // error. In such a case, the Scheduler will retry later.
116  // This is of course not optimal, but should only happen very
117  // seldom and thud won't affect the global efficiency
118  if ( sc.isFailure() )
119  DEBUG_MSG << "No instance of algorithm " << name << " could be retrieved in non-blocking mode" << endmsg;
120 
121  // if (m_lazyCreation ) {
122  // TODO: fill the lazyCreation part
123  // }
124  if ( sc.isSuccess() ) {
125  state_type requirements = m_resource_requirements[algo_id];
127  if ( requirements.is_subset_of( m_available_resources ) ) {
128  m_available_resources ^= requirements;
129  } else {
130  sc = StatusCode::FAILURE;
131  error() << "Failure to allocate resources of algorithm " << name << endmsg;
132  // in case of not reentrant, push it back. Reentrant ones are pushed back
133  // in all cases further down
134  if ( 0 != algo->cardinality() ) {
135  itQueueIAlgPtr->second->push( algo );
136  }
137  }
139  if ( 0 == algo->cardinality() ) {
140  // push back reentrant algos immediately as it can be reused
141  itQueueIAlgPtr->second->push( algo );
142  }
143  }
144  return sc;
145 }
146 
147 //---------------------------------------------------------------------------
148 
150 {
151 
152  std::hash<std::string> hash_function;
153  size_t algo_id = hash_function( name );
154 
155  // release resources used by the algorithm
159 
160  // release algorithm itself if not reentrant
161  if ( 0 != algo->cardinality() ) {
162  m_algqueue_map[algo_id]->push( algo );
163  }
164  return StatusCode::SUCCESS;
165 }
166 
167 //---------------------------------------------------------------------------
168 
170 {
174  return StatusCode::SUCCESS;
175 }
176 
177 //---------------------------------------------------------------------------
178 
180 {
184  return StatusCode::SUCCESS;
185 }
186 
187 //---------------------------------------------------------------------------
188 
190  unsigned int recursionDepth )
191 {
192 
194 
195  bool isGaudiSequencer( false );
196  bool isAthSequencer( false );
197 
198  if ( algo->isSequence() ) {
199  if ( algo->hasProperty( "ShortCircuit" ) )
200  isGaudiSequencer = true;
201  else if ( algo->hasProperty( "StopOverride" ) )
202  isAthSequencer = true;
203  }
204 
205  std::vector<Algorithm*>* subAlgorithms = algo->subAlgorithms();
206  if ( // we only want to add basic algorithms -> have no subAlgs
207  // and exclude the case of empty sequencers
208  ( subAlgorithms->empty() && !( isGaudiSequencer || isAthSequencer ) ) ) {
209 
210  alglist.emplace_back( algo );
211  // Only ForwardScheduler requires assembling the graph in AlgResourcePool.
212  // The AvalancheScheduler relies on the graph that is assembled by the PrecedenceSvc
213  if ( serviceLocator()->existsService( "ForwardSchedulerSvc" ) ) {
214  m_CFGraph->addAlgorithmNode( algo, parentName, false, false ).ignore();
215  DEBUG_MSG << std::string( recursionDepth, ' ' ) << algo->name() << " is not a sequencer. Appending it" << endmsg;
216  }
217  return sc;
218  }
219 
220  // Recursively unroll
221  ++recursionDepth;
222 
223  // Only ForwardScheduler requires assembling the graph in AlgResourcePool.
224  // The AvalancheScheduler relies on the graph that is assembled by the PrecedenceSvc
225  if ( serviceLocator()->existsService( "ForwardSchedulerSvc" ) ) {
226  DEBUG_MSG << std::string( recursionDepth, ' ' ) << algo->name() << " is a sequencer. Flattening it." << endmsg;
227 
228  bool modeOR = false;
229  bool allPass = false;
230  bool isLazy = false;
231  bool isSequential = false;
232 
233  if ( isGaudiSequencer ) {
234  modeOR = ( algo->getProperty( "ModeOR" ).toString() == "True" ) ? true : false;
235  allPass = ( algo->getProperty( "IgnoreFilterPassed" ).toString() == "True" ) ? true : false;
236  isLazy = ( algo->getProperty( "ShortCircuit" ).toString() == "True" ) ? true : false;
237  if ( allPass ) isLazy = false; // standard GaudiSequencer behavior on all pass is to execute everything
238  isSequential =
239  ( algo->hasProperty( "Sequential" ) && ( algo->getProperty( "Sequential" ).toString() == "True" ) );
240  } else if ( isAthSequencer ) {
241  modeOR = ( algo->getProperty( "ModeOR" ).toString() == "True" ) ? true : false;
242  allPass = ( algo->getProperty( "IgnoreFilterPassed" ).toString() == "True" ) ? true : false;
243  isLazy = ( algo->getProperty( "StopOverride" ).toString() == "True" ) ? false : true;
244  isSequential =
245  ( algo->hasProperty( "Sequential" ) && ( algo->getProperty( "Sequential" ).toString() == "True" ) );
246  }
247  sc = m_CFGraph->addDecisionHubNode( algo, parentName, !isSequential, isLazy, modeOR, allPass );
248  if ( sc.isFailure() ) {
249  error() << "Failed to add DecisionHub " << algo->name() << " to control flow graph" << endmsg;
250  return sc;
251  }
252  }
253 
254  for ( Algorithm* subalgo : *subAlgorithms ) {
255  sc = flattenSequencer( subalgo, alglist, algo->name(), recursionDepth );
256  if ( sc.isFailure() ) {
257  error() << "Algorithm " << subalgo->name() << " could not be flattened" << endmsg;
258  return sc;
259  }
260  }
261  return sc;
262 }
263 
264 //---------------------------------------------------------------------------
265 
267 {
268 
270  if ( !algMan.isValid() ) {
271  error() << "Algorithm manager could not be properly fetched." << endmsg;
272  return StatusCode::FAILURE;
273  }
274 
275  // Useful lambda not to repeat ourselves --------------------------
276  auto createAlg = [&algMan, this]( const std::string& item_type, const std::string& item_name, IAlgorithm*& algo ) {
277  StatusCode createAlgSc = algMan->createAlgorithm( item_type, item_name, algo, true, false );
278  if ( createAlgSc.isFailure() )
279  this->warning() << "Algorithm " << item_type << "/" << item_name << " could not be created." << endmsg;
280  };
281  // End of lambda --------------------------------------------------
282 
284 
285  // Fill the top alg list ----
286  const std::vector<std::string>& topAlgNames = m_topAlgNames.value();
287  for ( auto& name : topAlgNames ) {
288  IAlgorithm* algo( nullptr );
289 
291  const std::string& item_name = item.name();
292  const std::string& item_type = item.type();
293  SmartIF<IAlgorithm> algoSmartIF( algMan->algorithm( item_name, false ) );
294 
295  if ( !algoSmartIF.isValid() ) {
296  createAlg( item_type, item_name, algo );
297  algoSmartIF = algo;
298  }
299  // Init and start
300  algoSmartIF->sysInitialize().ignore();
301  m_topAlgList.push_back( algoSmartIF );
302  }
303  // Top Alg list filled ----
304 
305  // start forming the control flow graph by adding the head decision hub
306  // Only ForwardScheduler requires assembling the graph in AlgResourcePool.
307  // The AvalancheScheduler relies on the graph that is assembled by the PrecedenceSvc
308  if ( serviceLocator()->existsService( "ForwardSchedulerSvc" ) )
309  m_CFGraph->addHeadNode( "RootDecisionHub", true, false, true, true );
310 
311  // Now we unroll it ----
312  for ( auto& algoSmartIF : m_topAlgList ) {
313  Algorithm* algorithm = dynamic_cast<Algorithm*>( algoSmartIF.get() );
314  if ( !algorithm ) fatal() << "Conversion from IAlgorithm to Algorithm failed" << endmsg;
315  sc = flattenSequencer( algorithm, m_flatUniqueAlgList, "RootDecisionHub" );
316  }
317  // stupid O(N^2) unique-ification..
318  for ( auto i = begin( m_flatUniqueAlgList ); i != end( m_flatUniqueAlgList ); ++i ) {
319  auto n = next( i );
320  while ( n != end( m_flatUniqueAlgList ) ) {
321  if ( *n == *i )
323  else
324  ++n;
325  }
326  }
327  if ( msgLevel( MSG::DEBUG ) ) {
328  debug() << "List of algorithms is: " << endmsg;
329  for ( auto& algo : m_flatUniqueAlgList )
330  debug() << " o " << algo->type() << "/" << algo->name() << " @ " << algo << endmsg;
331  }
332 
333  // Unrolled ---
334 
335  // Now let's manage the clones
336  unsigned int resource_counter( 0 );
337  std::hash<std::string> hash_function;
338  for ( auto& ialgoSmartIF : m_flatUniqueAlgList ) {
339 
340  const std::string& item_name = ialgoSmartIF->name();
341 
342  verbose() << "Treating resource management and clones of " << item_name << endmsg;
343 
344  Algorithm* algo = dynamic_cast<Algorithm*>( ialgoSmartIF.get() );
345  if ( !algo ) fatal() << "Conversion from IAlgorithm to Algorithm failed" << endmsg;
346  const std::string& item_type = algo->type();
347 
348  size_t algo_id = hash_function( item_name );
350  m_algqueue_map[algo_id] = queue;
351 
352  // DP TODO Do it properly with SmartIFs, also in the queues
353  IAlgorithm* ialgo( ialgoSmartIF.get() );
354 
355  queue->push( ialgo );
356  m_algList.push_back( ialgo );
357  if ( ialgo->isClonable() ) {
358  m_n_of_allowed_instances[algo_id] = ialgo->cardinality();
359  } else {
360  if ( ialgo->cardinality() == 1 ) {
361  m_n_of_allowed_instances[algo_id] = 1;
362  } else {
363  if ( !m_overrideUnClonable ) {
364  info() << "Algorithm " << ialgo->name() << " is un-Clonable but Cardinality was set to "
365  << ialgo->cardinality() << ". Only creating 1 instance" << endmsg;
366  m_n_of_allowed_instances[algo_id] = 1;
367  } else {
368  warning() << "Overriding UnClonability of Algorithm " << ialgo->name() << ". Setting Cardinality to "
369  << ialgo->cardinality() << endmsg;
370  m_n_of_allowed_instances[algo_id] = ialgo->cardinality();
371  }
372  }
373  }
374  m_n_of_created_instances[algo_id] = 1;
375 
376  state_type requirements( 0 );
377 
378  for ( auto& resource_name : ialgo->neededResources() ) {
379  auto ret = m_resource_indices.emplace( resource_name, resource_counter );
380  // insert successful means == wasn't known before. So increment counter
381  if ( ret.second ) ++resource_counter;
382  // Resize for every algo according to the found resources
383  requirements.resize( resource_counter );
384  // in any case the return value holds the proper product index
385  requirements[ret.first->second] = true;
386  }
387 
388  m_resource_requirements[algo_id] = requirements;
389 
390  // potentially create clones; if not lazy creation we have to do it now
391  if ( !m_lazyCreation ) {
392  for ( unsigned int i = 1, end = m_n_of_allowed_instances[algo_id]; i < end; ++i ) {
393  debug() << "type/name to create clone of: " << item_type << "/" << item_name << endmsg;
394  IAlgorithm* ialgoClone( nullptr );
395  createAlg( item_type, item_name, ialgoClone );
396  ialgoClone->setIndex( i );
397  if ( ialgoClone->sysInitialize().isFailure() ) {
398  error() << "unable to initialize Algorithm clone " << ialgoClone->name() << endmsg;
399  sc = StatusCode::FAILURE;
400  // FIXME: should we delete this failed clone?
401  } else {
402  queue->push( ialgoClone );
403  m_n_of_created_instances[algo_id] += 1;
404  }
405  }
406  }
407  }
408 
409  // Now resize all the requirement bitsets to the same size
410  for ( auto& kv : m_resource_requirements ) {
411  kv.second.resize( resource_counter );
412  }
413 
414  // Set all resources to be available
415  m_available_resources.resize( resource_counter );
416  m_available_resources.set();
417 
418  return sc;
419 }
420 
421 //---------------------------------------------------------------------------
422 
424 {
426  for ( auto algoSmartIF : m_flatUniqueAlgList )
427  m_flatUniqueAlgPtrList.push_back( const_cast<IAlgorithm*>( algoSmartIF.get() ) );
428  return m_flatUniqueAlgPtrList;
429 }
430 
431 //---------------------------------------------------------------------------
432 
434 {
436  for ( auto algoSmartIF : m_topAlgList ) m_topAlgPtrList.push_back( const_cast<IAlgorithm*>( algoSmartIF.get() ) );
437  return m_topAlgPtrList;
438 }
439 
440 //---------------------------------------------------------------------------
441 
443 {
444  auto algBeginRun = [&]( SmartIF<IAlgorithm>& algoSmartIF ) -> StatusCode {
445  StatusCode sc = algoSmartIF->sysBeginRun();
446  if ( !sc.isSuccess() ) {
447  warning() << "beginRun() of algorithm " << algoSmartIF->name() << " failed" << endmsg;
448  return StatusCode::FAILURE;
449  }
450  return StatusCode::SUCCESS;
451  };
452  // Call the beginRun() method of all algorithms
453  for ( auto& algoSmartIF : m_flatUniqueAlgList ) {
454  if ( algBeginRun( algoSmartIF ).isFailure() ) return StatusCode::FAILURE;
455  }
456 
457  return StatusCode::SUCCESS;
458 }
459 
460 //---------------------------------------------------------------------------
461 
463 {
464 
465  auto algEndRun = [&]( SmartIF<IAlgorithm>& algoSmartIF ) -> StatusCode {
466  StatusCode sc = algoSmartIF->sysEndRun();
467  if ( !sc.isSuccess() ) {
468  warning() << "endRun() of algorithm " << algoSmartIF->name() << " failed" << endmsg;
469  return StatusCode::FAILURE;
470  }
471  return StatusCode::SUCCESS;
472  };
473  // Call the beginRun() method of all top algorithms
474  for ( auto& algoSmartIF : m_flatUniqueAlgList ) {
475  if ( algEndRun( algoSmartIF ).isFailure() ) return StatusCode::FAILURE;
476  }
477  for ( auto& algoSmartIF : m_topAlgList ) {
478  if ( algEndRun( algoSmartIF ).isFailure() ) return StatusCode::FAILURE;
479  }
480  return StatusCode::SUCCESS;
481 }
482 
483 //---------------------------------------------------------------------------
484 
486 {
487 
488  StatusCode stopSc = Service::stop();
489  if ( !stopSc.isSuccess() ) return stopSc;
490 
491  // sys-Stop the algos
492  for ( auto& ialgo : m_algList ) {
493  stopSc = ialgo->sysStop();
494  if ( stopSc.isFailure() ) {
495  error() << "Unable to stop Algorithm: " << ialgo->name() << endmsg;
496  return stopSc;
497  }
498  }
499  return StatusCode::SUCCESS;
500 }
ListAlg m_flatUniqueAlgList
The flat list of algorithms w/o clones.
StatusCode getProperty(Gaudi::Details::PropertyBase *p) const override
get the property
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:64
T unlock(T...args)
T empty(T...args)
const std::string & name() const override
The identifying name of the algorithm object.
Definition: Algorithm.cpp:731
const std::string & name() const override
Retrieve name of the service.
Definition: Service.cpp:289
MsgStream & info() const
shortcut for the method msgStream(MSG::INFO)
StatusCode start() override
Definition: Service.cpp:137
void addHeadNode(const std::string &headName, bool modeConcurrent, bool modePromptDecision, bool modeOR, bool allPass)
Add a node, which has no parents.
std::map< std::string, unsigned int > m_resource_indices
bool isSuccess() const
Test for a status code of SUCCESS.
Definition: StatusCode.h:75
StatusCode addDecisionHubNode(Algorithm *daughterAlgo, const std::string &parentName, bool modeConcurrent, bool modePromptDecision, bool modeOR, bool allPass)
Add a node, which aggregates decisions of direct daughter nodes.
bool hasProperty(const std::string &name) const override
Return true if we have a property with the given name.
MsgStream & verbose() const
shortcut for the method msgStream(MSG::VERBOSE)
std::mutex m_resource_mutex
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 beginRun() override
virtual bool existsService(const std::string &name) const =0
Check the existence of a service given a service name.
StatusCode stop() override
T end(T...args)
virtual StatusCode getProperty(Gaudi::Details::PropertyBase *p) const =0
Get the property by property.
StatusCode endRun() override
The AlgResourcePool is a concrete implementation of the IAlgResourcePool interface.
bool isFailure() const
Test for a status code of FAILURE.
Definition: StatusCode.h:86
state_type m_available_resources
Gaudi::Property< bool > m_overrideUnClonable
virtual StatusCode sysInitialize()=0
Initialization method invoked by the framework.
auto begin(reverse_wrapper< T > &w)
Definition: reverse.h:58
STL class.
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:28
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...
auto end(reverse_wrapper< T > &w)
Definition: reverse.h:64
virtual void setIndex(const unsigned int &idx)=0
Set instantiation index of Alg.
std::list< IAlgorithm * > getFlatAlgList() override
#define DECLARE_SERVICE_FACTORY(x)
Definition: Service.h:211
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:130
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::vector< Algorithm * > * subAlgorithms() const
List of sub-algorithms. Returns a pointer to a vector of (sub) Algorithms.
Definition: Algorithm.cpp:776
Base class from which all concrete algorithm classes should be derived.
Definition: Algorithm.h:78
T find(T...args)
StatusCode decodeTopAlgs()
Decode the top alg list.
MsgStream & debug() const
shortcut for the method msgStream(MSG::DEBUG)
bool isValid() const
Allow for check if smart pointer is valid.
Definition: SmartIF.h:68
bool isSequence() const override
Are we a Sequence?
Definition: Algorithm.h:218
const std::string & type() const
StatusCode flattenSequencer(Algorithm *sequencer, ListAlg &alglist, const std::string &parentName, unsigned int recursionDepth=0)
Recursively flatten an algList.
T emplace(T...args)
StatusCode acquireAlgorithm(const std::string &name, IAlgorithm *&algo, bool blocking=false) override
Acquire a certain algorithm using its name.
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:85
std::map< size_t, unsigned int > m_n_of_created_instances
#define DEBUG_MSG
const std::string & name() const
StatusCode initialize() override
MsgStream & fatal() const
shortcut for the method msgStream(MSG::FATAL)
void ignore() const
Definition: StatusCode.h:109
ListAlg m_topAlgList
The list of top algorithms.
const std::string & type() const override
The type of the algorithm object.
Definition: Algorithm.h:166
MSG::Level msgLevel() const
get the output level from the embedded MsgStream
StatusCode addAlgorithmNode(Algorithm *daughterAlgo, const std::string &parentName, bool inverted, bool allPass)
Add algorithm node.
SmartIF< ISvcLocator > & serviceLocator() const override
Retrieve pointer to service locator.
Definition: Service.cpp:292
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:209
StatusCode releaseAlgorithm(const std::string &name, IAlgorithm *&algo) override
Release a certain algorithm.
concurrency::recursive_CF::ControlFlowGraph * m_CFGraph
OMG yet another hack.
Gaudi::Property< bool > m_lazyCreation
T emplace_back(T...args)