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 Files
2 
3 // Framework
4 #include "AlgResourcePool.h"
8 
9 // C++
10 #include <functional>
11 #include <queue>
12 
13 // DP TODO: Manage smartifs and not pointers to algos
14 
15 // Instantiation of a static factory class used by clients to create instances of this service
17 
18 #define ON_DEBUG if ( msgLevel( MSG::DEBUG ) )
19 #define DEBUG_MSG ON_DEBUG debug()
20 
21 //---------------------------------------------------------------------------
22 
23 // destructor
25 
26  for (auto& algoId_algoQueue : m_algqueue_map){
27  auto* queue = algoId_algoQueue.second;
28  delete queue;
29  }
30 
31  delete m_EFGraph;
32 }
33 
34 //---------------------------------------------------------------------------
35 
36 // initialize the pool with the list of algos known to the IAlgManager
38 
40  if (!sc.isSuccess())
41  warning () << "Base class could not be started" << endmsg;
42 
43  // Try to recover the topAlgList from the ApplicationManager for backward-compatibility
44  if (m_topAlgNames.value().empty()){
45  info() << "TopAlg list empty. Recovering the one of Application Manager" << endmsg;
46  const Gaudi::Utils::TypeNameString appMgrName("ApplicationMgr/ApplicationMgr");
47  SmartIF<IProperty> appMgrProps (serviceLocator()->service(appMgrName));
48  m_topAlgNames.assign(appMgrProps->getProperty("TopAlg"));
49  }
50 
51  // XXX: Prepare empty Control Flow graph
52  const std::string& name = "ExecutionFlowGraph";
55 
56  sc = decodeTopAlgs();
57  if (sc.isFailure())
58  warning() << "Algorithms could not be properly decoded." << endmsg;
59 
60  // let's assume all resources are there
62  return StatusCode::SUCCESS;
63 }
64 
65 //---------------------------------------------------------------------------
66 
68 
69  StatusCode startSc = Service::start();
70  if ( ! startSc.isSuccess() ) return startSc;
71 
72  // sys-Start the algos
73  for (auto& ialgo : m_algList){
74  startSc = ialgo->sysStart();
75  if (startSc.isFailure()){
76  error() << "Unable to start Algorithm: " << ialgo->name() << endmsg;
77  return startSc;
78  }
79  }
80  return StatusCode::SUCCESS;
81 }
82 
83 //---------------------------------------------------------------------------
84 
86 
87  std::hash<std::string> hash_function;
88  size_t algo_id = hash_function(name);
89  auto itQueueIAlgPtr = m_algqueue_map.find(algo_id);
90 
91  if (itQueueIAlgPtr == m_algqueue_map.end()) {
92  error() << "Algorithm " << name << " requested, but not recognised"
93  << endmsg;
94  algo = nullptr;
95  return StatusCode::FAILURE;
96  }
97 
98  StatusCode sc;
99  if (blocking) {
100  itQueueIAlgPtr->second->pop(algo);
101  sc = StatusCode::SUCCESS;
102  } else {
103  sc = itQueueIAlgPtr->second->try_pop(algo);
104  }
105 
106  if(sc.isFailure())
107  DEBUG_MSG << "No instance of algorithm " << name << " could be retrieved in non-blocking mode" << endmsg;
108 
109  // if (m_lazyCreation ) {
110  // TODO: fill the lazyCreation part
111  // }
112  if (sc.isSuccess()){
113  state_type requirements = m_resource_requirements[algo_id];
115  if (requirements.is_subset_of(m_available_resources)) {
116  m_available_resources^=requirements;
117  } else {
118  sc = StatusCode::FAILURE;
119  error() << "Failure to allocate resources of algorithm " << name << endmsg;
120  itQueueIAlgPtr->second->push(algo);
121  }
123  }
124  return sc;
125 }
126 
127 //---------------------------------------------------------------------------
128 
130 
131  std::hash<std::string> hash_function;
132  size_t algo_id = hash_function(name);
133 
134  // release resources used by the algorithm
138 
139  //release algorithm itself
140  m_algqueue_map[algo_id]->push(algo);
141  return StatusCode::SUCCESS;
142  }
143 
144 //---------------------------------------------------------------------------
145 
150  return StatusCode::SUCCESS;
151 }
152 
153 //---------------------------------------------------------------------------
154 
159  return StatusCode::SUCCESS;
160 }
161 
162 //---------------------------------------------------------------------------
163 
164 StatusCode AlgResourcePool::flattenSequencer(Algorithm* algo, ListAlg& alglist, const std::string& parentName, unsigned int recursionDepth){
165 
167 
168  std::vector<Algorithm*>* subAlgorithms = algo->subAlgorithms();
169  if ( // we only want to add basic algorithms -> have no subAlgs
170  // and exclude the case of empty GaudiSequencers
171  (subAlgorithms->empty() and not (algo->type() == "GaudiSequencer"))
172  // we want to add non-empty GaudiAtomicSequencers
173  or (algo->type() == "GaudiAtomicSequencer" and not subAlgorithms->empty())){
174 
175  DEBUG_MSG << std::string(recursionDepth, ' ') << algo->name() << " is "
176  << (algo->type() != "GaudiAtomicSequencer" ? "not a sequencer" : "an atomic sequencer")
177  << ". Appending it" << endmsg;
178 
179  alglist.emplace_back(algo);
180  m_EFGraph->addAlgorithmNode(algo, parentName, false, false).ignore();
181  return sc;
182  }
183 
184  // Recursively unroll
185  ++recursionDepth;
186  DEBUG_MSG << std::string(recursionDepth, ' ') << algo->name() << " is a sequencer. Flattening it." << endmsg;
187  bool modeOR = false;
188  bool allPass = false;
189  bool isLazy = false;
190  if ("GaudiSequencer" == algo->type()) {
191  modeOR = (algo->getProperty("ModeOR").toString() == "True")? true : false;
192  allPass = (algo->getProperty("IgnoreFilterPassed").toString() == "True")? true : false;
193  isLazy = (algo->getProperty("ShortCircuit").toString() == "True")? true : false;
194  if (allPass) isLazy = false; // standard GaudiSequencer behavior on all pass is to execute everything
195  }
196  sc = m_EFGraph->addDecisionHubNode(algo, parentName, modeOR, allPass, isLazy);
197  if (sc.isFailure()) {
198  error() << "Failed to add DecisionHub " << algo->name() << " to execution flow graph" << endmsg;
199  return sc;
200  }
201 
202  for (Algorithm* subalgo : *subAlgorithms ) {
203  sc = flattenSequencer(subalgo,alglist,algo->name(),recursionDepth);
204  if (sc.isFailure()) {
205  error() << "Algorithm " << subalgo->name() << " could not be flattened" << endmsg;
206  return sc;
207  }
208  }
209  return sc;
210 }
211 
212 //---------------------------------------------------------------------------
213 
215 
217  if (!algMan.isValid()){
218  error() << "Algorithm manager could not be properly fetched." << endmsg;
219  return StatusCode::FAILURE;
220  }
221 
222  // Useful lambda not to repeat ourselves --------------------------
223  auto createAlg = [&algMan,this] (const std::string& item_type,
224  const std::string& item_name,
225  IAlgorithm*& algo){
226  StatusCode createAlgSc = algMan->createAlgorithm(item_type,
227  item_name,
228  algo,
229  true,
230  false);
231  if (createAlgSc.isFailure())
232  this->warning() << "Algorithm " << item_type << "/" << item_name
233  << " could not be created." << endmsg;
234  };
235  // End of lambda --------------------------------------------------
236 
238 
239  // Fill the top alg list ----
240  const std::vector<std::string>& topAlgNames = m_topAlgNames.value();
241  for (auto& name : topAlgNames) {
242  IAlgorithm* algo(nullptr);
243 
245  const std::string& item_name = item.name();
246  const std::string& item_type = item.type();
247  SmartIF<IAlgorithm> algoSmartIF (algMan->algorithm(item_name,false));
248 
249  if (!algoSmartIF.isValid()){
250  createAlg(item_type,item_name,algo);
251  algoSmartIF = algo;
252  }
253  // Init and start
254  algoSmartIF->sysInitialize();
255  m_topAlgList.push_back(algoSmartIF);
256  }
257  // Top Alg list filled ----
258 
259  // start forming the control flow graph by adding the head node
260  m_EFGraph->addHeadNode("EVENT LOOP",true,true,false);
261 
262  // Now we unroll it ----
263  for (auto& algoSmartIF : m_topAlgList){
264  Algorithm* algorithm = dynamic_cast<Algorithm*> (algoSmartIF.get());
265  if (!algorithm) fatal() << "Conversion from IAlgorithm to Algorithm failed" << endmsg;
266  sc = flattenSequencer(algorithm, m_flatUniqueAlgList, "EVENT LOOP");
267  }
268  if (msgLevel(MSG::DEBUG)){
269  debug() << "List of algorithms is: " << endmsg;
270  for (auto& algo : m_flatUniqueAlgList)
271  debug() << " o " << algo->type() << "/" << algo->name() << " @ " << algo << endmsg;
272  }
273 
274  // Unrolled ---
275 
276  // Now let's manage the clones
277  unsigned int resource_counter(0);
278  std::hash<std::string> hash_function;
279  for (auto& ialgoSmartIF : m_flatUniqueAlgList) {
280 
281  const std::string& item_name = ialgoSmartIF->name();
282 
283  verbose() << "Treating resource management and clones of " << item_name << endmsg;
284 
285  Algorithm* algo = dynamic_cast<Algorithm*> ( ialgoSmartIF.get() );
286  if (!algo) fatal() << "Conversion from IAlgorithm to Algorithm failed" << endmsg;
287  const std::string& item_type = algo->type();
288 
289  size_t algo_id = hash_function(item_name);
291  m_algqueue_map[algo_id] = queue;
292 
293  // DP TODO Do it properly with SmartIFs, also in the queues
294  IAlgorithm* ialgo(ialgoSmartIF.get());
295 
296  queue->push(ialgo);
297  m_algList.push_back(ialgo);
298  m_n_of_allowed_instances[algo_id] = ialgo->cardinality();
299  m_n_of_created_instances[algo_id] = 1;
300 
301  state_type requirements(0);
302 
303  for (auto& resource_name : ialgo->neededResources()){
304  auto ret = m_resource_indices.insert(std::pair<std::string, unsigned int>(resource_name,resource_counter));
305  // insert successful means == wasn't known before. So increment counter
306  if (ret.second==true) {
307  ++resource_counter;
308  }
309  // Resize for every algo according to the found resources
310  requirements.resize(resource_counter);
311  // in any case the return value holds the proper product index
312  requirements[ret.first->second] = true;
313 
314  }
315 
316  m_resource_requirements[algo_id] = requirements;
317 
318  // potentially create clones; if not lazy creation we have to do it now
319  if (!m_lazyCreation) {
320  for (unsigned int i =1, end =ialgo->cardinality();i<end; ++i){
321  debug() << "type/name to create clone of: " << item_type << "/"
322  << item_name << endmsg;
323  IAlgorithm* ialgoClone(nullptr);
324  createAlg(item_type,item_name,ialgoClone);
325  ialgoClone->setIndex(i);
326  if (ialgoClone->sysInitialize().isFailure()) {
327  error() << "unable to initialize Algorithm clone "
328  << ialgoClone->name() << endmsg;
329  sc = StatusCode::FAILURE;
330  // FIXME: should we delete this failed clone?
331  } else {
332  queue->push(ialgoClone);
333  m_n_of_created_instances[algo_id]+=1;
334  }
335  }
336  }
337 
339 
340  }
341 
342  // Now resize all the requirement bitsets to the same size
343  for (auto& kv : m_resource_requirements) {
344  kv.second.resize(resource_counter);
345  }
346 
347  // Set all resources to be available
348  m_available_resources.resize(resource_counter);
349  m_available_resources.set();
350 
351  return sc;
352 }
353 
354 //---------------------------------------------------------------------------
355 
358  for (auto algoSmartIF :m_flatUniqueAlgList )
359  m_flatUniqueAlgPtrList.push_back(const_cast<IAlgorithm*>(algoSmartIF.get()));
360  return m_flatUniqueAlgPtrList;
361 }
362 
363 //---------------------------------------------------------------------------
364 
367  for (auto algoSmartIF :m_topAlgList )
368  m_topAlgPtrList.push_back(const_cast<IAlgorithm*>(algoSmartIF.get()));
369  return m_topAlgPtrList;
370 }
371 
372 //---------------------------------------------------------------------------
373 
375  auto algBeginRun = [&] (SmartIF<IAlgorithm>& algoSmartIF) -> StatusCode {
376  StatusCode sc = algoSmartIF->sysBeginRun();
377  if (!sc.isSuccess()) {
378  warning() << "beginRun() of algorithm " << algoSmartIF->name() << " failed" << endmsg;
379  return StatusCode::FAILURE;
380  }
381  return StatusCode::SUCCESS;
382  };
383  // Call the beginRun() method of all algorithms
384  for (auto& algoSmartIF : m_flatUniqueAlgList ) {
385  if (algBeginRun(algoSmartIF).isFailure())
386  return StatusCode::FAILURE;
387  }
388 
389  return StatusCode::SUCCESS;
390 }
391 
392 //---------------------------------------------------------------------------
393 
395 
396  auto algEndRun = [&] (SmartIF<IAlgorithm>& algoSmartIF) -> StatusCode {
397  StatusCode sc = algoSmartIF->sysEndRun();
398  if (!sc.isSuccess()) {
399  warning() << "endRun() of algorithm " << algoSmartIF->name() << " failed" << endmsg;
400  return StatusCode::FAILURE;
401  }
402  return StatusCode::SUCCESS;
403  };
404  // Call the beginRun() method of all top algorithms
405  for (auto& algoSmartIF : m_flatUniqueAlgList ) {
406  if (algEndRun(algoSmartIF).isFailure())
407  return StatusCode::FAILURE;
408  }
409  for (auto& algoSmartIF : m_topAlgList ) {
410  if (algEndRun(algoSmartIF).isFailure())
411  return StatusCode::FAILURE;
412  }
413  return StatusCode::SUCCESS;
414 }
415 
416 //---------------------------------------------------------------------------
417 
419 
420  StatusCode stopSc = Service::stop();
421  if ( ! stopSc.isSuccess() ) return stopSc;
422 
423  // sys-Stop the algos
424  for (auto& ialgo : m_algList){
425  stopSc = ialgo->sysStop();
426  if (stopSc.isFailure()){
427  error() << "Unable to stop Algorithm: " << ialgo->name() << endmsg;
428  return stopSc;
429  }
430  }
431  return StatusCode::SUCCESS;
432 }
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:725
const std::string & name() const override
Retrieve name of the service.
Definition: Service.cpp:289
StatusCode addDecisionHubNode(Algorithm *daughterAlgo, const std::string &parentName, bool modeOR, bool allPass, bool isLazy)
Add a node, which aggregates decisions of direct daughter nodes.
MsgStream & info() const
shortcut for the method msgStream(MSG::INFO)
StatusCode start() override
Definition: Service.cpp:137
std::map< std::string, unsigned int > m_resource_indices
bool isSuccess() const
Test for a status code of SUCCESS.
Definition: StatusCode.h:74
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
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:84
state_type m_available_resources
virtual StatusCode sysInitialize()=0
Initialization method invoked by the framework.
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:26
concurrency::ExecutionFlowGraph * m_EFGraph
OMG yet another hack.
std::map< size_t, state_type > m_resource_requirements
StatusCode start() override
T lock(T...args)
~AlgResourcePool() override
std::list< IAlgorithm * > m_topAlgPtrList
The top list of algorithms.
auto end(reverse_wrapper< T > &w)
Definition: reverse.h:49
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:242
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:27
StatusCode acquireResource(const std::string &name) override
Acquire a certain resource.
std::map< size_t, concurrentQueueIAlgPtr * > m_algqueue_map
T insert(T...args)
const std::vector< Algorithm * > * subAlgorithms() const
List of sub-algorithms. Returns a pointer to a vector of (sub) Algorithms.
Definition: Algorithm.cpp:801
Base class from which all concrete algorithm classes should be derived.
Definition: Algorithm.h:78
T find(T...args)
StatusCode addAlgorithmNode(Algorithm *daughterAlgo, const std::string &parentName, bool inverted, bool allPass)
Add algorithm node.
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:62
const std::string & type() const
StatusCode flattenSequencer(Algorithm *sequencer, ListAlg &alglist, const std::string &parentName, unsigned int recursionDepth=0)
Recursively flatten an algList.
StatusCode acquireAlgorithm(const std::string &name, IAlgorithm *&algo, bool blocking=false) override
Acquire a certain algorithm using its name.
void addHeadNode(const std::string &headName, bool modeOR, bool allPass, bool isLazy)
Add a node, which has no parents.
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:106
ListAlg m_topAlgList
The list of top algorithms.
const std::string & type() const override
The type of the algorithm object.
Definition: Algorithm.h:165
MSG::Level msgLevel() const
get the output level from the embedded MsgStream
void attachAlgorithmsToNodes(const std::string &algo_name, const T &container)
Attach pointers to real Algorithms (and their clones) to Algorithm nodes of the graph.
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:244
StatusCode releaseAlgorithm(const std::string &name, IAlgorithm *&algo) override
Release a certain algorithm.
Gaudi::Property< bool > m_lazyCreation
T emplace_back(T...args)