The Gaudi Framework  v29r0 (ff2e7097)
GaudiParallelizer.cpp
Go to the documentation of this file.
1 // Include files
2 // From Gaudi
8 
9 #include "GaudiParallelizer.h"
10 
11 // ----------------------------------------------------------------------------
12 // Implementation file for class: GaudiParallelizer
13 //
14 // 09/12/2011: Illya Shapoval
15 // ----------------------------------------------------------------------------
17 
18 // ============================================================================
19 // Standard constructor, initializes variables
20 // ============================================================================
21 GaudiParallelizer::GaudiParallelizer( const std::string& name, ISvcLocator* pSvcLocator )
22  : GaudiAlgorithm( name, pSvcLocator )
23 {
24  m_names.declareUpdateHandler( &GaudiParallelizer::membershipHandler, this );
25 }
26 
27 // ============================================================================
28 // Initialization
29 // ============================================================================
31 {
32  if ( msgLevel( MSG::DEBUG ) ) debug() << "==> Initialize" << endmsg;
33  StatusCode sc = GaudiAlgorithm::initialize(); // must be executed first
34  if ( sc.isFailure() ) return sc; // error printed already by GaudiAlgorithm
35 
36  StatusCode status = decodeNames();
37  if ( !status.isSuccess() ) return status;
38 
39  m_timerTool = tool<ISequencerTimerTool>( "SequencerTimerTool" );
40  if ( m_timerTool->globalTiming() ) m_measureTime = true;
41 
42  if ( m_measureTime ) {
45  } else {
47  m_timerTool = 0;
48  }
49 
50  //== Initialize the algorithms
52  for ( itE = m_entries.begin(); m_entries.end() != itE; itE++ ) {
53  Algorithm* myAlg = itE->algorithm();
54  if ( m_measureTime ) {
55  itE->setTimer( m_timerTool->addTimer( myAlg->name() ) );
56  }
57 
58  status = myAlg->sysInitialize();
59  if ( !status.isSuccess() ) {
60  return Error( "Can not initialize " + myAlg->name(), status );
61  }
62  }
63 
65 
66  if ( m_nthreads != 0 ) {
67  // Construct the TBB task scheduler with m_nthreads threads
68  tbb::task_scheduler_init init( m_nthreads );
69  } else {
70  m_nthreads = tbb::task_scheduler_init::default_num_threads();
71  }
72 
73  if ( msgLevel( MSG::DEBUG ) )
74  debug() << "Number of threads set to be used in the TBB thread pool is " << m_nthreads << endmsg;
75  return StatusCode::SUCCESS;
76 }
77 
78 // ============================================================================
79 // Main execution
80 // ============================================================================
82 {
84 
85  if ( msgLevel( MSG::DEBUG ) ) debug() << "==> Execute algorithms in parallel" << endmsg;
86 
87  for ( std::vector<AlgorithmEntry>::iterator itE = m_entries.begin(); m_entries.end() != itE; ++itE ) {
88  Algorithm* myAlg = itE->algorithm();
89  if ( !myAlg->isEnabled() ) continue;
90  if ( !myAlg->isExecuted() ) {
91 
92  m_task_group.run( boost::bind( &AlgorithmEntry::run, boost::ref( *itE ), boost::ref( *this ) ) );
93  }
94  }
95 
96  m_task_group.wait();
97  if ( msgLevel( MSG::DEBUG ) ) debug() << "==> Joining parallel algorithm tasks" << endmsg;
98 
99  for ( std::vector<AlgorithmEntry>::const_iterator it = m_entries.begin(); it != m_entries.end(); ++it ) {
100  if ( msgLevel( MSG::DEBUG ) )
101  debug() << "Algorithm wrapper " << &*it << " around the algorithm " << it->algorithm()->name()
102  << " received return status code " << it->m_returncode << endmsg;
103  }
104 
105  for ( std::vector<AlgorithmEntry>::const_iterator it = m_entries.begin(); it != m_entries.end(); ++it )
106  if ( !( it->m_returncode.isSuccess() ) ) return it->m_returncode;
107 
108  setExecuted( true );
110  return StatusCode::SUCCESS;
111 }
112 
113 // ============================================================================
114 // Finalize
115 // ============================================================================
117 {
118  if ( msgLevel( MSG::DEBUG ) ) debug() << "==> Finalize" << endmsg;
119 
120  return GaudiAlgorithm::finalize(); // must be called after all other actions
121 }
122 
123 // ============================================================================
124 
126 {
127 
129  m_entries.clear();
130 
131  //== Get the "Context" option if in the file...
132  auto jos = service<IJobOptionsSvc>( "JobOptionsSvc" );
133  bool addedContext = false; //= Have we added the context ?
134  bool addedRootInTES = false; //= Have we added the rootInTES ?
135 
136  //= Get the Application manager, to see if algorithm exist
137  auto appMgr = service<IAlgManager>( "ApplicationMgr" );
138  const std::vector<std::string>& nameVector = m_names.value();
140  for ( it = nameVector.begin(); nameVector.end() != it; it++ ) {
142  const std::string& theName = typeName.name();
143  const std::string& theType = typeName.type();
144 
145  //== Check whether the specified algorithm already exists. If not, create it
147  SmartIF<IAlgorithm> myIAlg = appMgr->algorithm( typeName, false ); // do not create it now
148  if ( !myIAlg.isValid() ) {
149  //== Set the Context if not in the jobOptions list
150  if ( !context().empty() || !rootInTES().empty() ) {
151  bool foundContext = false;
152  bool foundRootInTES = false;
153  const auto properties = jos->getProperties( theName );
154  if ( properties ) {
155  // Iterate over the list to set the options
156  for ( const auto& p : *properties ) {
157  if ( "Context" == p->name() ) {
158  foundContext = true;
159  }
160  if ( "RootInTES" == p->name() ) {
161  foundRootInTES = true;
162  }
163  }
164  }
165  if ( !foundContext && !context().empty() ) {
166  Gaudi::Property<std::string> contextProperty( "Context", context() );
167  jos->addPropertyToCatalogue( theName, contextProperty ).ignore();
168  addedContext = true;
169  }
170  if ( !foundRootInTES && !rootInTES().empty() ) {
171  Gaudi::Property<std::string> rootInTESProperty( "RootInTES", rootInTES() );
172  jos->addPropertyToCatalogue( theName, rootInTESProperty ).ignore();
173  addedRootInTES = true;
174  }
175  }
176 
177  Algorithm* myAlg = nullptr;
178  result = createSubAlgorithm( theType, theName, myAlg );
179  // (MCl) this should prevent bug #35199... even if I didn't manage to
180  // reproduce it with a simple test.
181  if ( result.isSuccess() ) myIAlg = myAlg;
182  } else {
183  Algorithm* myAlg = dynamic_cast<Algorithm*>( myIAlg.get() );
184  if ( myAlg ) {
185  subAlgorithms()->push_back( myAlg );
186  // when the algorithm is not created, the ref count is short by one, so we have to fix it.
187  myAlg->addRef();
188  }
189  }
190 
191  //== Remove the property, in case this is not a GaudiAlgorithm...
192  if ( addedContext ) {
193  jos->removePropertyFromCatalogue( theName, "Context" ).ignore();
194  addedContext = false;
195  }
196  if ( addedRootInTES ) {
197  jos->removePropertyFromCatalogue( theName, "RootInTES" ).ignore();
198  addedRootInTES = false;
199  }
200 
201  // propagate the sub-algorithm into own state.
202  if ( result.isSuccess() && Gaudi::StateMachine::INITIALIZED <= FSMState() && myIAlg.isValid() &&
203  Gaudi::StateMachine::INITIALIZED > myIAlg->FSMState() ) {
204  StatusCode sc = myIAlg->sysInitialize();
205  if ( sc.isFailure() ) {
206  result = sc;
207  }
208  }
209 
210  // propagate the sub-algorithm into own state.
211  if ( result.isSuccess() && Gaudi::StateMachine::RUNNING <= FSMState() && myIAlg.isValid() &&
212  Gaudi::StateMachine::RUNNING > myIAlg->FSMState() ) {
213  StatusCode sc = myIAlg->sysStart();
214  if ( sc.isFailure() ) {
215  result = sc;
216  }
217  }
218 
219  //== Is it an Algorithm ? Strange test...
220  if ( result.isSuccess() ) {
221  // TODO: (MCl) it is possible to avoid the dynamic_cast in most of the
222  // cases by keeping the result of createSubAlgorithm.
223  Algorithm* myAlg = dynamic_cast<Algorithm*>( myIAlg.get() );
224  if ( myAlg != 0 ) {
225  // Note: The reference counting is kept by the system of sub-algorithms
226  m_entries.push_back( AlgorithmEntry( myAlg ) );
227  if ( msgLevel( MSG::DEBUG ) ) debug() << "Added algorithm " << theName << endmsg;
228  } else {
229  warning() << theName << " is not an Algorithm - failed dynamic_cast" << endmsg;
230  final = StatusCode::FAILURE;
231  }
232  } else {
233  warning() << "Unable to find or create " << theName << endmsg;
234  final = result;
235  }
236  }
237  //== Print the list of algorithms
238  MsgStream& msg = info();
239  if ( m_modeOR ) msg << "OR ";
240  msg << "Member list: ";
242  ostream_joiner( msg, m_entries, ", ", []( MsgStream& msg, const AlgorithmEntry& entry ) -> MsgStream& {
243  Algorithm* myAlg = entry.algorithm();
244  auto myAlgType = System::typeinfoName( typeid( *myAlg ) );
245  if ( myAlg->name() != myAlgType ) {
246  msg << myAlgType << "/";
247  }
248  return msg << myAlg->name();
249  } );
250  if ( !context().empty() ) msg << ", with context '" << context() << "'";
251  if ( !rootInTES().empty() ) msg << ", with rootInTES '" << rootInTES() << "'";
252  msg << endmsg;
253  return final;
254 }
255 
256 //=========================================================================
257 // Interface for the Property manager
258 //=========================================================================
260 {
261  // no action for not-yet initialized sequencer
263  return;
264  } // RETURN
265 
266  decodeNames().ignore();
267 
268  if ( !m_measureTime ) {
269  return;
270  } // RETURN
271 
272  // add the entries into timer table:
273 
274  if ( 0 == m_timerTool ) {
275  m_timerTool = tool<ISequencerTimerTool>( "SequencerTimerTool" );
276  }
277 
278  if ( m_timerTool->globalTiming() ) m_measureTime = true;
279 
282 
283  for ( std::vector<AlgorithmEntry>::iterator itE = m_entries.begin(); m_entries.end() != itE; ++itE ) {
284  itE->setTimer( m_timerTool->addTimer( itE->algorithm()->name() ) );
285  }
286 
288 }
289 //=============================================================================
StatusCode initialize() override
Algorithm initialization.
Gaudi::Property< bool > m_measureTime
StatusCode execute() override
Algorithm execution.
Definition of the MsgStream class used to transmit messages.
Definition: MsgStream.h:24
MsgStream & msg() const
shortcut for the method msgStream(MSG::INFO)
T empty(T...args)
Gaudi::Property< bool > m_modeOR
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.
StatusCode createSubAlgorithm(const std::string &type, const std::string &name, Algorithm *&pSubAlg)
Create a sub algorithm.
Definition: Algorithm.cpp:837
Algorithm * algorithm() const
const std::string & name() const override
The identifying name of the algorithm object.
Definition: Algorithm.cpp:731
Implementation of property with value of concrete type.
Definition: Property.h:319
virtual StatusCode sysStart()=0
Startup method invoked by the framework.
const std::string & rootInTES() const
Returns the "rootInTES" string.
Definition: GaudiCommon.h:708
bool isExecuted() const override
Has this algorithm been executed since the last reset?
Definition: Algorithm.cpp:741
MsgStream & info() const
shortcut for the method msgStream(MSG::INFO)
GAUDI_API const std::string typeinfoName(const std::type_info &)
Get platform independent information about the class type.
Definition: System.cpp:329
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:75
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.
STL namespace.
StatusCode decodeNames()
Decode a vector of string.
const std::string & context() const
Returns the "context" string. Used to identify different processing states.
Definition: GaudiCommon.h:704
virtual void increaseIndent()=0
Increase the indentation of the name.
T end(T...args)
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
virtual StatusCode sysInitialize()=0
Initialization method invoked by the framework.
Provide serialization function (output only) for some common STL classes (vectors, lists, pairs, maps) plus GaudiUtils::Map and GaudiUtils::HashMap.
STL class.
StatusCode finalize() override
Algorithm finalization.
TYPE * get() const
Get interface pointer.
Definition: SmartIF.h:82
T push_back(T...args)
bool isEnabled() const override
Is this algorithm enabled or disabled?
Definition: Algorithm.cpp:760
Helper class to parse a string of format "type/name".
MsgStream & warning() const
shortcut for the method msgStream(MSG::WARNING)
This class is used for returning status codes from appropriate routines.
Definition: StatusCode.h:28
StatusCode finalize() override
standard finalization method
#define DECLARE_ALGORITHM_FACTORY(x)
Definition: Algorithm.h:629
The useful base class for data processing algorithms.
PropertyBase base class allowing PropertyBase* collections to be "homogeneous".
Definition: Property.h:32
Gaudi::Property< unsigned short > m_nthreads
Stream & ostream_joiner(Stream &os, Iterator first, Iterator last, Separator sep, OutputElement output=OutputElement{})
Definition: SerializeSTL.h:40
tbb::task_group m_task_group
TBB task group.
virtual void start(int index)=0
start the counter, i.e.
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
STL class.
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
T begin(T...args)
const std::string & type() const
std::vector< AlgorithmEntry > m_entries
List of algorithms to process.
appMgr
Definition: IOTest.py:94
void setExecuted(bool state) const override
Set the executed flag to the specified state.
Definition: Algorithm.cpp:747
void membershipHandler(Gaudi::Details::PropertyBase &theProp)
for asynchronous changes in the list of algorithms
Gaudi::Property< std::vector< std::string > > m_names
ISequencerTimerTool * m_timerTool
Pointer to the timer tool.
int m_timer
Timer number for the sequencer.
const std::string & name() const
void ignore() const
Definition: StatusCode.h:109
std::string typeName(const std::type_info &typ)
Definition: Dictionary.cpp:23
MSG::Level msgLevel() const
get the output level from the embedded MsgStream
StatusCode sysInitialize() override
Initialization method invoked by the framework.
Definition: Algorithm.cpp:78
virtual double stop(int index)=0
stop the counter, return the elapsed time
StatusCode release(const IInterface *interface) const
Manual forced (and &#39;safe&#39;) release of the active tool or service.
void run(GaudiParallelizer &prlzr)
Thread task executor method to wrap an algorithm execution in.
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition: MsgStream.h:209
Gaudi::StateMachine::State FSMState() const override
returns the current state of the algorithm
Definition: Algorithm.h:191