GaudiSequencer.cpp
Go to the documentation of this file.
1 // Include files
2 
3 // from Gaudi
4 #include "GaudiKernel/IAlgManager.h"
5 #include "GaudiAlg/GaudiSequencer.h"
6 #include "GaudiAlg/ISequencerTimerTool.h"
7 #include "GaudiKernel/IJobOptionsSvc.h"
8 
9 
10 
11 namespace
12 {
13 
14  //TODO: this adds C++14 'make_unique'... remove once we move to C++14...
15  template<typename T, typename ...Args>
16  std::unique_ptr<T> make_unique_( Args&& ...args ) {
17  return std::unique_ptr<T>( new T( std::forward<Args>(args)... ) );
18  }
19 
20  bool isDefault(const std::string& s) { return s.empty(); }
21  constexpr bool isDefault(double x) { return x == 0; }
22 
23  // utility class to populate some properties in the job options service
24  // for a given instance name in case those options are not explicitly
25  // set a-priori (effectively inheriting their values from the GaudiSequencer)
26  class populate_JobOptionsSvc_t {
27  std::vector<std::unique_ptr<Property>> m_props;
28  IJobOptionsSvc* m_jos;
29  std::string m_name;
30 
31  template <typename T> void process(T&& t) {
32  static_assert( std::tuple_size<T>::value == 2, "Expecting an std::tuple key-value pair" );
34  using prop_t = SimpleProperty<type>;
35  if (!isDefault(std::get<1>(t))) m_props.push_back( make_unique_<prop_t>( std::get<0>(t), std::get<1>(t) ) ) ;
36  }
37  template <typename T, typename... Args> void process(T&& t, Args&&... args) {
38  process(std::forward<T>(t)); process(std::forward<Args>(args)...);
39  }
40  void check_veto() { // avoid changing properties expliclty present in the JOS...
41  const auto* props = m_jos->getProperties(m_name);
42  if (!props) return;
43  for ( const auto& i : *props ) {
44  auto j = std::find_if( std::begin(m_props), std::end(m_props),
45  [&i](const std::unique_ptr<Property>& prop) {
46  return prop->name() == i->name();
47  } );
48  if (j==std::end(m_props)) continue;
49  m_props.erase( j );
50  if (m_props.empty()) break; // done!
51  }
52  }
53 
54  public:
55  template <typename... Args>
56  populate_JobOptionsSvc_t( std::string name, IJobOptionsSvc* jos, Args&&... args ) : m_jos{jos},m_name{ std::move(name) } {
57  process(std::forward<Args>(args)...);
58  if (!m_props.empty()) check_veto();
59  std::for_each( std::begin(m_props), std::end(m_props), [&](const std::unique_ptr<Property>& i ) {
60  m_jos->addPropertyToCatalogue( m_name, *i ).ignore();
61  } );
62  }
63  ~populate_JobOptionsSvc_t() {
64  std::for_each( std::begin(m_props), std::end(m_props), [&](const std::unique_ptr<Property>& i ) {
65  m_jos->removePropertyFromCatalogue( m_name, i->name() ).ignore();
66  } );
67  }
68  };
69 
70  template <typename Stream, typename Container, typename Separator, typename Transform>
71  Stream& ostream_joiner(Stream& os, const Container& c, Separator sep, Transform trans )
72  {
73  auto first = std::begin(c); auto last = std::end(c);
74  if (first!=last) { os << trans(*first); ++first; }
75  for (;first!=last;++first) os << sep << trans(*first);
76  return os;
77  }
78 
79 }
80 
81 
82 //-----------------------------------------------------------------------------
83 // Implementation file for class : GaudiSequencer
84 //
85 // 2004-05-13 : Olivier Callot
86 //-----------------------------------------------------------------------------
87 
88 //=============================================================================
89 // Standard constructor, initializes variables
90 //=============================================================================
92  ISvcLocator* pSvcLocator)
93  : GaudiAlgorithm ( name , pSvcLocator )
94 {
95  declareProperty( "Members" , m_names );
96  declareProperty( "ModeOR" , m_modeOR = false );
97  declareProperty( "IgnoreFilterPassed" , m_ignoreFilter = false );
98  declareProperty( "MeasureTime" , m_measureTime = false );
99  declareProperty( "ReturnOK" , m_returnOK = false );
100  declareProperty( "ShortCircuit" , m_shortCircuit = true );
101 
103 }
104 //=============================================================================
105 // Initialisation. Check parameters
106 //=============================================================================
109 
110  if (msgLevel(MSG::DEBUG)) debug() << "==> Initialise" << endmsg;
111 
112  StatusCode status = decodeNames();
113  if ( !status.isSuccess() ) return status;
114 
115  m_timerTool = tool<ISequencerTimerTool>( "SequencerTimerTool" );
116  if ( m_timerTool->globalTiming() ) m_measureTime = true;
117 
118  if ( m_measureTime ) {
121  } else {
122  release( m_timerTool );
123  m_timerTool = nullptr;
124  }
125 
126  //== Initialize the algorithms
127  for (auto& entry : m_entries ) {
128  if ( m_measureTime ) {
129  entry.setTimer( m_timerTool->addTimer( entry.algorithm()->name() ) );
130  }
131 
132  status = entry.algorithm()->sysInitialize();
133  if ( !status.isSuccess() ) {
134  return Error( "Can not initialize " + entry.algorithm()->name(),
135  status );
136  }
137  }
139 
140  return StatusCode::SUCCESS;
141 }
142 
143 //=============================================================================
144 // Main execution
145 //=============================================================================
147 
149 
150  if (msgLevel(MSG::DEBUG)) debug() << "==> Execute" << endmsg;
151 
152  StatusCode result = StatusCode(StatusCode::SUCCESS, true);
153 
154  bool seqPass = !m_modeOR; // for OR, result will be false, unless (at least) one is true
155  // for AND, result will be true, unless (at least) one is false
156  // also see comment below ....
157 
158  for (auto& entry : m_entries) {
159  Algorithm* myAlg = entry.algorithm();
160  if ( ! myAlg->isEnabled() ) continue;
161  if ( ! myAlg->isExecuted() ) {
162  if ( m_measureTime ) m_timerTool->start( entry.timer() );
163  result = myAlg->sysExecute();
164  if ( m_measureTime ) m_timerTool->stop( entry.timer() );
165  myAlg->setExecuted( true );
166  if ( ! result.isSuccess() ) break; //== Abort and return bad status
167  }
168  //== Check the returned status
169  if ( !m_ignoreFilter ) {
170  bool passed = myAlg->filterPassed();
171  if (msgLevel(MSG::VERBOSE))
172  verbose() << "Algorithm " << myAlg->name() << " returned filter passed "
173  << (passed ? "true" : "false") << endmsg;
174  if ( entry.reverse() ) passed = !passed;
175 
176 
177  //== indicate our own result. For OR, exit as soon as true.
178  // If no more, will exit with false.
179  //== for AND, exit as soon as false. Else, will be true (default)
180 
181  // if not short-circuiting, make sure we latch iPass to 'true' in
182  // OR mode (i.e. it is sufficient for one item to be true in order
183  // to be true at the end, and thus we start out at 'false'), and latch
184  // to 'false' in AND mode (i.e. it is sufficient for one item to
185  // be false to the false in the end, and thus we start out at 'true')
186  // -- i.e. we should not just blindly return the 'last' passed status!
187 
188  // or to put it another way: in OR mode, we don't care about things
189  // which are false, as they leave our current state alone (provided
190  // we stared as 'false'!), and in AND mode, we keep our current
191  // state until someone returns 'false' (provided we started as 'true')
192  if ( m_modeOR ? passed : !passed ) {
193  seqPass = passed;
194  if (msgLevel(MSG::VERBOSE))
195  verbose() << "SeqPass is now " << (seqPass ? "true" : "false") << endmsg;
196  if (m_shortCircuit) break;
197  }
198  }
199 
200  }
201  if (msgLevel(MSG::VERBOSE))
202  verbose() << "SeqPass is " << (seqPass ? "true" : "false") << endmsg;
203  if ( !m_ignoreFilter && !m_entries.empty() ) setFilterPassed( seqPass );
204  setExecuted( true );
205 
207 
208  return m_returnOK ? (result.ignore(), StatusCode::SUCCESS) : result;
209 }
210 
211 //=============================================================================
212 // Finalize
213 //=============================================================================
215 
216  if (msgLevel(MSG::DEBUG)) debug() << "==> Finalize" << endmsg;
217  return GaudiAlgorithm::finalize();
218 }
219 
220 //=========================================================================
221 // Execute the beginRun of every algorithm
222 //=========================================================================
224 
225  if ( !isEnabled() ) return StatusCode::SUCCESS;
226  if (msgLevel(MSG::DEBUG)) debug() << "==> beginRun" << endmsg;
227  return StatusCode::SUCCESS;
228 }
229 
230 //=========================================================================
231 // Execute the endRun() of every algorithm
232 //=========================================================================
234 
235  if ( !isEnabled() ) return StatusCode::SUCCESS;
236  if (msgLevel(MSG::DEBUG)) debug() << "==> endRun" << endmsg;
237  return StatusCode::SUCCESS;
238 }
239 
240 //=========================================================================
241 // Decode the input names and fills the m_algs vector.
242 //=========================================================================
244 
246  m_entries.clear();
247 
248  //== Get the "Context" option if in the file...
249  auto jos = service<IJobOptionsSvc>( "JobOptionsSvc" );
250 
251  //= Get the Application manager, to see if algorithm exist
252  auto appMgr = service<IAlgManager>("ApplicationMgr");
253  for (const auto& item : m_names.value() ) {
255  const std::string &theName = typeName.name();
256  const std::string &theType = typeName.type();
257 
258  //== Check wether the specified algorithm already exists. If not, create it
260  SmartIF<IAlgorithm> myIAlg = appMgr->algorithm(typeName, false); // do not create it now
261  if ( !myIAlg ) {
262  // ensure some magic properties are set while we create the subalgorithm so
263  // that it effectively inherites 'our' settings -- if they have non-default
264  // values... and are not set explicitly already.
265  populate_JobOptionsSvc_t populate_guard{ theName, jos,
266  std::forward_as_tuple( "Context", context() ),
267  std::forward_as_tuple( "RootInTES", rootInTES() ),
268  std::forward_as_tuple( "GlobalTimeOffset", globalTimeOffset() )
269  };
270  Algorithm *myAlg = nullptr;
271  result = createSubAlgorithm( theType, theName, myAlg );
272  myIAlg = myAlg; // ensure that myIAlg.isValid() from here onwards!
273  } else {
274  Algorithm *myAlg = dynamic_cast<Algorithm*>(myIAlg.get());
275  if (myAlg) {
276  subAlgorithms()->push_back(myAlg);
277  // when the algorithm is not created, the ref count is short by one, so we have to fix it.
278  myAlg->addRef();
279  }
280  }
281 
282  // propagate the sub-algorithm into own state.
283  if ( result.isSuccess () &&
284  Gaudi::StateMachine::INITIALIZED <= FSMState() &&
285  myIAlg &&
286  Gaudi::StateMachine::INITIALIZED > myIAlg->FSMState() )
287  {
288  StatusCode sc = myIAlg->sysInitialize() ;
289  if ( sc.isFailure() ) { result = sc ; }
290  }
291 
292  // propagate the sub-algorithm into own state.
293  if ( result.isSuccess () &&
294  Gaudi::StateMachine::RUNNING <= FSMState() &&
295  myIAlg &&
296  Gaudi::StateMachine::RUNNING > myIAlg->FSMState() )
297  {
298  StatusCode sc = myIAlg->sysStart () ;
299  if ( sc.isFailure() ) { result = sc ; }
300  }
301 
302  //== Is it an Algorithm ? Strange test...
303  if ( result.isSuccess() ) {
304  // TODO: (MCl) it is possible to avoid the dynamic_cast in most of the
305  // cases by keeping the result of createSubAlgorithm.
306  Algorithm* myAlg = dynamic_cast<Algorithm*>(myIAlg.get());
307  if (myAlg) {
308  // Note: The reference counting is kept by the system of sub-algorithms
309  m_entries.emplace_back( myAlg );
310  if (msgLevel(MSG::DEBUG)) debug () << "Added algorithm " << theName << endmsg;
311  } else {
312  warning() << theName << " is not an Algorithm - failed dynamic_cast"
313  << endmsg;
314  final = StatusCode::FAILURE;
315  }
316  } else {
317  warning() << "Unable to find or create " << theName << endmsg;
318  final = result;
319  }
320 
321  }
322 
323  //== Print the list of algorithms
324  MsgStream& msg = info();
325  if ( m_modeOR ) msg << "OR ";
326  msg << "Member list: ";
327  ostream_joiner( msg, m_entries, ", ", [](const AlgorithmEntry& e) {
328  Algorithm* alg = e.algorithm();
329  std::string typ = System::typeinfoName( typeid( *alg) ) ;
330  return ( alg->name() == typ ) ? alg->name() : ( typ + "/" + alg->name() );
331  } );
332  if ( !isDefault(context()) ) msg << ", with context '" << context() << "'";
333  if ( !isDefault(rootInTES()) ) msg << ", with rootInTES '" << rootInTES() << "'";
334  if ( !isDefault(globalTimeOffset()) ) msg << ", with globalTimeOffset " << globalTimeOffset();
335  msg << endmsg;
336 
337  return final;
338 }
339 
340 //=========================================================================
341 // Interface for the Property manager
342 //=========================================================================
344 {
345  // no action for not-yet initialized sequencer
346  if ( Gaudi::StateMachine::INITIALIZED > FSMState() ) { return ; } // RETURN
347 
348  decodeNames().ignore();
349 
350  if ( !m_measureTime ) { return ; } // RETURN
351 
352  // add the entries into timer table:
353 
354  if ( !m_timerTool )
355  { m_timerTool = tool<ISequencerTimerTool>( "SequencerTimerTool" ) ; }
356 
357  if ( m_timerTool->globalTiming() ) m_measureTime = true;
358 
361 
362  for ( auto& entry : m_entries )
363  {
364  entry.setTimer( m_timerTool->addTimer( entry.algorithm()->name() ) );
365  }
366 
368 
369 }
370 //=============================================================================
void membershipHandler(Property &theProp)
for asynchronous changes in the list of algorithms
tuple c
Definition: gaudirun.py:392
Definition of the MsgStream class used to transmit messages.
Definition: MsgStream.h:24
virtual const std::vector< const Property * > * getProperties(const std::string &client) const =0
Get the properties associated to a given client.
MsgStream & verbose() const
shortcut for the method msgStream(MSG::VERBOSE)
StatusCode execute() override
Algorithm execution.
bool m_shortCircuit
Indicates whether to stop processing as soon as possible, or to always execute all subalgorithms...
The ISvcLocator is the interface implemented by the Service Factory in the Application Manager to loc...
Definition: ISvcLocator.h:25
virtual void decreaseIndent()=0
Decrease the indentation of the name.
virtual StatusCode sysStart()=0
Startup method invoked by the framework.
const std::string & rootInTES() const
Returns the "rootInTES" string.
Definition: GaudiCommon.h:725
bool m_returnOK
Forces the sequencer to return a good status.
bool m_modeOR
Indicates that the OR is wanted instead of AND.
const std::string & name() const
property name
Definition: Property.h:45
StatusCode initialize() override
Algorithm initialization.
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition: MsgStream.h:244
virtual int addTimer(const std::string &name)=0
add a timer entry with the specified name
StatusCode initialize() override
standard initialization method
auto begin(reverse_wrapper< T > &w)
Definition: reverse.h:45
bool isSuccess() const
Test for a status code of SUCCESS.
Definition: StatusCode.h:76
GAUDI_API const std::string typeinfoName(const std::type_info &)
Get platform independent information about the class type.
Definition: System.cpp:299
StatusCode Error(const std::string &msg, const StatusCode st=StatusCode::FAILURE, const size_t mx=10) const
Print the error message and return with the given StatusCode.
MsgStream & warning() const
shortcut for the method msgStream(MSG::WARNING)
bool filterPassed() const override
Did this algorithm pass or fail its filter criterion for the last event?
Definition: Algorithm.cpp:817
const std::string & context() const
Returns the "context" string. Used to identify different processing states.
Definition: GaudiCommon.h:721
virtual void increaseIndent()=0
Increase the indentation of the name.
Algorithm * algorithm() const
bool isFailure() const
Test for a status code of FAILURE.
Definition: StatusCode.h:86
virtual bool globalTiming()=0
returns the flag telling that global timing is wanted
StatusCode endRun() override
Algorithm endRun.
virtual StatusCode sysInitialize()=0
Initialization method invoked by the framework.
MsgStream & msg() const
shortcut for the method msgStream(MSG::INFO)
const std::string & name() const override
The identifying name of the algorithm object.
Definition: Algorithm.cpp:792
SimpleProperty concrete class which implements the full Property interface.
Definition: HistoProperty.h:13
TYPE * get() const
Get interface pointer.
Definition: SmartIF.h:76
Helper class to parse a string of format "type/name".
Definition: TypeNameString.h:9
void setExecuted(bool state) override
Set the executed flag to the specified state.
Definition: Algorithm.cpp:804
Main interface for the JobOptions service.
MsgStream & debug() const
shortcut for the method msgStream(MSG::DEBUG)
auto end(reverse_wrapper< T > &w)
Definition: reverse.h:47
unsigned long addRef() override
Reference Interface instance.
Definition: implements.h:43
This class is used for returning status codes from appropriate routines.
Definition: StatusCode.h:26
StatusCode sysExecute() override
The actions to be performed by the algorithm on an event.
Definition: Algorithm.cpp:545
bool m_measureTime
Flag to measure time.
bool isExecuted() const override
Has this algorithm been executed since the last reset?
Definition: Algorithm.cpp:800
StatusCode finalize() override
standard finalization method
The useful base class for data processing algorithms.
StatusCode finalize() override
Algorithm finalization.
const TYPE & value() const
explicit conversion
Definition: Property.h:341
StatusCode decodeNames()
Decode a vector of string.
virtual void start(int index)=0
start the counter, i.e.
Base class from which all concrete algorithm classes should be derived.
Definition: Algorithm.h:61
Property base class allowing Property* collections to be "homogeneous".
Definition: Property.h:38
list args
Definition: gaudirun.py:291
bool isEnabled() const override
Is this algorithm enabled or disabled?
Definition: Algorithm.cpp:813
const std::string & type() const
virtual StatusCode removePropertyFromCatalogue(const std::string &client, const std::string &name)=0
Remove a property from the JobOptions catalog.
virtual StatusCode addPropertyToCatalogue(const std::string &client, const Property &property)=0
Add a property into the JobOptions catalog.
string s
Definition: gaudirun.py:246
tuple item
print s1,s2
Definition: ana.py:146
virtual void declareUpdateHandler(std::function< void(Property &)> fun)
set new callback for update
Definition: Property.cpp:71
tuple appMgr
Definition: IOTest.py:83
GaudiSequencer(const std::string &name, ISvcLocator *pSvcLocator)
Standard constructor.
const std::string & name() const
double globalTimeOffset() const
Returns the "globalTimeOffset" double.
Definition: GaudiCommon.h:727
void ignore() const
Definition: StatusCode.h:108
std::string typeName(const std::type_info &typ)
Definition: Dictionary.cpp:21
MsgStream & info() const
shortcut for the method msgStream(MSG::INFO)
list i
Definition: ana.py:128
virtual double stop(int index)=0
stop the counter, return the elapsed time
StatusCode release(const IInterface *interface) const
Manual forced (and 'safe') release of the active tool or service.
bool m_ignoreFilter
True if one continues always.
std::vector< AlgorithmEntry > m_entries
List of algorithms to process.
int m_timer
Timer number for the sequencer.
ISequencerTimerTool * m_timerTool
Pointer to the timer tool.
string type
Definition: gaudirun.py:151
StatusCode beginRun() override
Algorithm beginRun.
StringArrayProperty m_names
Input string, list of algorithms.
MSG::Level msgLevel() const
get the output level from the embedded MsgStream