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 
163  //DF: if we have a context set by GaudiHive scheduler propagate it to the children
164  if(getContext())
165  myAlg->setContext(getContext());
166 
167  if ( m_measureTime ) m_timerTool->start( entry.timer() );
168  result = myAlg->sysExecute();
169  if ( m_measureTime ) m_timerTool->stop( entry.timer() );
170  myAlg->setExecuted( true );
171  if ( ! result.isSuccess() ) break; //== Abort and return bad status
172  }
173  //== Check the returned status
174  if ( !m_ignoreFilter ) {
175  bool passed = myAlg->filterPassed();
176  if (msgLevel(MSG::VERBOSE))
177  verbose() << "Algorithm " << myAlg->name() << " returned filter passed "
178  << (passed ? "true" : "false") << endmsg;
179  if ( entry.reverse() ) passed = !passed;
180 
181 
182  //== indicate our own result. For OR, exit as soon as true.
183  // If no more, will exit with false.
184  //== for AND, exit as soon as false. Else, will be true (default)
185 
186  // if not short-circuiting, make sure we latch iPass to 'true' in
187  // OR mode (i.e. it is sufficient for one item to be true in order
188  // to be true at the end, and thus we start out at 'false'), and latch
189  // to 'false' in AND mode (i.e. it is sufficient for one item to
190  // be false to the false in the end, and thus we start out at 'true')
191  // -- i.e. we should not just blindly return the 'last' passed status!
192 
193  // or to put it another way: in OR mode, we don't care about things
194  // which are false, as they leave our current state alone (provided
195  // we stared as 'false'!), and in AND mode, we keep our current
196  // state until someone returns 'false' (provided we started as 'true')
197  if ( m_modeOR ? passed : !passed ) {
198  seqPass = passed;
199  if (msgLevel(MSG::VERBOSE))
200  verbose() << "SeqPass is now " << (seqPass ? "true" : "false") << endmsg;
201  if (m_shortCircuit) break;
202  }
203  }
204 
205  }
206  if (msgLevel(MSG::VERBOSE))
207  verbose() << "SeqPass is " << (seqPass ? "true" : "false") << endmsg;
208  if ( !m_ignoreFilter && !m_entries.empty() ) setFilterPassed( seqPass );
209  setExecuted( true );
210 
212 
213  return m_returnOK ? (result.ignore(), StatusCode::SUCCESS) : result;
214 }
215 
216 //=============================================================================
217 // Finalize
218 //=============================================================================
220 
221  if (msgLevel(MSG::DEBUG)) debug() << "==> Finalize" << endmsg;
222  return GaudiAlgorithm::finalize();
223 }
224 
225 //=========================================================================
226 // Execute the beginRun of every algorithm
227 //=========================================================================
229 
230  if ( !isEnabled() ) return StatusCode::SUCCESS;
231  if (msgLevel(MSG::DEBUG)) debug() << "==> beginRun" << endmsg;
232  return StatusCode::SUCCESS;
233 }
234 
235 //=========================================================================
236 // Execute the endRun() of every algorithm
237 //=========================================================================
239 
240  if ( !isEnabled() ) return StatusCode::SUCCESS;
241  if (msgLevel(MSG::DEBUG)) debug() << "==> endRun" << endmsg;
242  return StatusCode::SUCCESS;
243 }
244 
245 //=========================================================================
246 // Decode the input names and fills the m_algs vector.
247 //=========================================================================
249 
251  m_entries.clear();
252 
253  //== Get the "Context" option if in the file...
254  auto jos = service<IJobOptionsSvc>( "JobOptionsSvc" );
255 
256  //= Get the Application manager, to see if algorithm exist
257  auto appMgr = service<IAlgManager>("ApplicationMgr");
258  for (const auto& item : m_names.value() ) {
260  const std::string &theName = typeName.name();
261  const std::string &theType = typeName.type();
262 
263  //== Check wether the specified algorithm already exists. If not, create it
265  SmartIF<IAlgorithm> myIAlg = appMgr->algorithm(typeName, false); // do not create it now
266  if ( !myIAlg ) {
267  // ensure some magic properties are set while we create the subalgorithm so
268  // that it effectively inherites 'our' settings -- if they have non-default
269  // values... and are not set explicitly already.
270  populate_JobOptionsSvc_t populate_guard{ theName, jos,
271  std::forward_as_tuple( "Context", context() ),
272  std::forward_as_tuple( "RootInTES", rootInTES() ),
273  std::forward_as_tuple( "GlobalTimeOffset", globalTimeOffset() )
274  };
275  Algorithm *myAlg = nullptr;
276  result = createSubAlgorithm( theType, theName, myAlg );
277  myIAlg = myAlg; // ensure that myIAlg.isValid() from here onwards!
278  } else {
279  Algorithm *myAlg = dynamic_cast<Algorithm*>(myIAlg.get());
280  if (myAlg) {
281  subAlgorithms()->push_back(myAlg);
282  // when the algorithm is not created, the ref count is short by one, so we have to fix it.
283  myAlg->addRef();
284  }
285  }
286 
287  // propagate the sub-algorithm into own state.
288  if ( result.isSuccess () &&
289  Gaudi::StateMachine::INITIALIZED <= FSMState() &&
290  myIAlg &&
291  Gaudi::StateMachine::INITIALIZED > myIAlg->FSMState() )
292  {
293  StatusCode sc = myIAlg->sysInitialize() ;
294  if ( sc.isFailure() ) { result = sc ; }
295  }
296 
297  // propagate the sub-algorithm into own state.
298  if ( result.isSuccess () &&
299  Gaudi::StateMachine::RUNNING <= FSMState() &&
300  myIAlg &&
301  Gaudi::StateMachine::RUNNING > myIAlg->FSMState() )
302  {
303  StatusCode sc = myIAlg->sysStart () ;
304  if ( sc.isFailure() ) { result = sc ; }
305  }
306 
307  //== Is it an Algorithm ? Strange test...
308  if ( result.isSuccess() ) {
309  // TODO: (MCl) it is possible to avoid the dynamic_cast in most of the
310  // cases by keeping the result of createSubAlgorithm.
311  Algorithm* myAlg = dynamic_cast<Algorithm*>(myIAlg.get());
312  if (myAlg) {
313  // Note: The reference counting is kept by the system of sub-algorithms
314  m_entries.emplace_back( myAlg );
315  if (msgLevel(MSG::DEBUG)) debug () << "Added algorithm " << theName << endmsg;
316  } else {
317  warning() << theName << " is not an Algorithm - failed dynamic_cast"
318  << endmsg;
319  final = StatusCode::FAILURE;
320  }
321  } else {
322  warning() << "Unable to find or create " << theName << endmsg;
323  final = result;
324  }
325 
326  }
327 
328  //== Print the list of algorithms
329  MsgStream& msg = info();
330  if ( m_modeOR ) msg << "OR ";
331  msg << "Member list: ";
332  ostream_joiner( msg, m_entries, ", ", [](const AlgorithmEntry& e) {
333  Algorithm* alg = e.algorithm();
334  std::string typ = System::typeinfoName( typeid( *alg) ) ;
335  return ( alg->name() == typ ) ? alg->name() : ( typ + "/" + alg->name() );
336  } );
337  if ( !isDefault(context()) ) msg << ", with context '" << context() << "'";
338  if ( !isDefault(rootInTES()) ) msg << ", with rootInTES '" << rootInTES() << "'";
339  if ( !isDefault(globalTimeOffset()) ) msg << ", with globalTimeOffset " << globalTimeOffset();
340  msg << endmsg;
341 
342  return final;
343 }
344 
345 //=========================================================================
346 // Interface for the Property manager
347 //=========================================================================
349 {
350  // no action for not-yet initialized sequencer
351  if ( Gaudi::StateMachine::INITIALIZED > FSMState() ) { return ; } // RETURN
352 
353  decodeNames().ignore();
354 
355  if ( !m_measureTime ) { return ; } // RETURN
356 
357  // add the entries into timer table:
358 
359  if ( !m_timerTool )
360  { m_timerTool = tool<ISequencerTimerTool>( "SequencerTimerTool" ) ; }
361 
362  if ( m_timerTool->globalTiming() ) m_measureTime = true;
363 
366 
367  for ( auto& entry : m_entries )
368  {
369  entry.setTimer( m_timerTool->addTimer( entry.algorithm()->name() ) );
370  }
371 
373 
374 }
375 //=============================================================================
Stream & ostream_joiner(Stream &os, Iterator first, Iterator last, Separator sep, OutputElement output=OutputElement{})
Definition: SerializeSTL.h:35
void membershipHandler(Property &theProp)
for asynchronous changes in the list of algorithms
tuple c
Definition: gaudirun.py:391
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.
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition: MsgStream.h:244
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.
virtual Property & declareUpdateHandler(std::function< void(Property &)> fun)
set new callback for update
Definition: Property.cpp:72
const std::string & name() const
property name
Definition: Property.h:45
StatusCode initialize() override
Algorithm initialization.
virtual int addTimer(const std::string &name)=0
add a timer entry with the specified name
StatusCode initialize() override
standard initialization method
bool isSuccess() const
Test for a status code of SUCCESS.
Definition: StatusCode.h:76
auto begin(reverse_wrapper< T > &w)
Definition: reverse.h:45
GAUDI_API const std::string typeinfoName(const std::type_info &)
Get platform independent information about the class type.
Definition: System.cpp:297
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:948
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.
void setContext(EventContext *context)
set the context
Definition: Algorithm.h:556
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:919
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:935
Main interface for the JobOptions service.
MsgStream & debug() const
shortcut for the method msgStream(MSG::DEBUG)
unsigned long addRef() override
Reference Interface instance.
Definition: implements.h:44
auto end(reverse_wrapper< T > &w)
Definition: reverse.h:47
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:652
bool m_measureTime
Flag to measure time.
bool isExecuted() const override
Has this algorithm been executed since the last reset?
Definition: Algorithm.cpp:931
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:77
Property base class allowing Property* collections to be "homogeneous".
Definition: Property.h:38
list args
Definition: gaudirun.py:290
bool isEnabled() const override
Is this algorithm enabled or disabled?
Definition: Algorithm.cpp:944
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:245
tuple item
print s1,s2
Definition: ana.py:146
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