All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
GaudiParallelizer.cpp
Go to the documentation of this file.
1 // Include files
2 // From Gaudi
3 #include "GaudiKernel/AlgFactory.h"
4 #include "GaudiKernel/IAlgManager.h"
5 #include "GaudiKernel/IJobOptionsSvc.h"
6 #include "GaudiAlg/ISequencerTimerTool.h"
7 
8 #include "GaudiParallelizer.h"
9 
10 // ----------------------------------------------------------------------------
11 // Implementation file for class: GaudiParallelizer
12 //
13 // 09/12/2011: Illya Shapoval
14 // ----------------------------------------------------------------------------
16 
17 // ============================================================================
18 // Standard constructor, initializes variables
19 // ============================================================================
20 GaudiParallelizer::GaudiParallelizer(const std::string& name, ISvcLocator* pSvcLocator)
21  : GaudiAlgorithm(name, pSvcLocator)
22  , m_timerTool( 0 )
23 {
24  declareProperty( "Members" , m_names );
25  declareProperty( "ModeOR" , m_modeOR = false );
26  declareProperty( "MeasureTime" , m_measureTime = false );
27  declareProperty( "ReturnOK" , m_returnOK = false );
28  declareProperty( "NumberOfThreads", m_nthreads = 0 );
29 
30  m_names.declareUpdateHandler (&GaudiParallelizer::membershipHandler, this );
31 }
32 
33 // ============================================================================
34 // Destructor
35 // ============================================================================
37 
38 // ============================================================================
39 // Initialization
40 // ============================================================================
42  if ( msgLevel(MSG::DEBUG) ) debug() << "==> Initialize" << endmsg;
43  StatusCode sc = GaudiAlgorithm::initialize(); // must be executed first
44  if ( sc.isFailure() ) return sc; // error printed already by GaudiAlgorithm
45 
46  StatusCode status = decodeNames();
47  if ( !status.isSuccess() ) return status;
48 
49  m_timerTool = tool<ISequencerTimerTool>( "SequencerTimerTool" );
50  if ( m_timerTool->globalTiming() ) m_measureTime = true;
51 
52  if ( m_measureTime ) {
55  } else {
57  m_timerTool = 0;
58  }
59 
60  //== Initialize the algorithms
61  std::vector<AlgorithmEntry>::iterator itE;
62  for ( itE = m_entries.begin(); m_entries.end() != itE; itE++ ) {
63  Algorithm* myAlg = itE->algorithm();
64  if ( m_measureTime ) {
65  itE->setTimer( m_timerTool->addTimer( myAlg->name() ) );
66  }
67 
68  status = myAlg->sysInitialize();
69  if ( !status.isSuccess() ) {
70  return Error( "Can not initialize " + myAlg->name(),
71  status );
72  }
73  }
74 
76 
77  if ( m_nthreads != 0 ) {
78  // Construct the TBB task scheduler with m_nthreads threads
79  tbb::task_scheduler_init init( m_nthreads );
80  }
81  else {
82  m_nthreads = tbb::task_scheduler_init::default_num_threads();
83  }
84 
85  if ( msgLevel(MSG::DEBUG) ) debug() << "Number of threads set to be used in the TBB thread pool is "
86  << m_nthreads << endmsg;
87  return StatusCode::SUCCESS;
88 }
89 
90 // ============================================================================
91 // Main execution
92 // ============================================================================
95 
96  if ( msgLevel(MSG::DEBUG) ) debug() << "==> Execute algorithms in parallel" << endmsg;
97 
98  for (std::vector<AlgorithmEntry>::iterator itE = m_entries.begin(); m_entries.end() != itE; ++itE ) {
99  Algorithm* myAlg = itE->algorithm();
100  if ( ! myAlg->isEnabled() ) continue;
101  if ( ! myAlg->isExecuted() ) {
102 
103  m_task_group.run(boost::bind(&AlgorithmEntry::run,
104  boost::ref(*itE),
105  boost::ref(*this)));
106  }
107  }
108 
109  m_task_group.wait();
110  if ( msgLevel(MSG::DEBUG) ) debug() << "==> Joining parallel algorithm tasks" << endmsg;
111 
112  for( std::vector<AlgorithmEntry>::const_iterator it = m_entries.begin(); it != m_entries.end(); ++it ){
113  if ( msgLevel(MSG::DEBUG) ) debug() << "Algorithm wrapper " << &*it
114  << " around the algorithm " << it->algorithm()->name()
115  << " received return status code " << it->m_returncode
116  << endmsg;
117  }
118 
119  for( std::vector<AlgorithmEntry>::const_iterator it = m_entries.begin(); it != m_entries.end(); ++it )
120  if ( !(it->m_returncode.isSuccess()) ) return it->m_returncode;
121 
122  setExecuted( true );
124  return StatusCode::SUCCESS;
125 }
126 
127 // ============================================================================
128 // Finalize
129 // ============================================================================
131  if ( msgLevel(MSG::DEBUG) ) debug() << "==> Finalize" << endmsg;
132 
133  return GaudiAlgorithm::finalize(); // must be called after all other actions
134 }
135 
136 // ============================================================================
137 
139 
141  m_entries.clear();
142 
143  //== Get the "Context" option if in the file...
144  IJobOptionsSvc* jos = svc<IJobOptionsSvc>( "JobOptionsSvc" );
145  bool addedContext = false; //= Have we added the context ?
146  bool addedRootInTES = false; //= Have we added the rootInTES ?
147  bool addedGlobalTimeOffset = false; //= Have we added the globalTimeOffset ?
148 
149 
150  //= Get the Application manager, to see if algorithm exist
151  IAlgManager* appMgr = svc<IAlgManager>("ApplicationMgr");
152  const std::vector<std::string>& nameVector = m_names.value();
153  std::vector<std::string>::const_iterator it;
154  for ( it = nameVector.begin(); nameVector.end() != it; it++ ) {
156  const std::string &theName = typeName.name();
157  const std::string &theType = typeName.type();
158 
159  //== Check whether the specified algorithm already exists. If not, create it
161  SmartIF<IAlgorithm> myIAlg = appMgr->algorithm(typeName, false); // do not create it now
162  if ( !myIAlg.isValid() ) {
163  //== Set the Context if not in the jobOptions list
164  if ( "" != context() ||
165  "" != rootInTES() ||
166  0.0 != globalTimeOffset() ) {
167  bool foundContext = false;
168  bool foundRootInTES = false;
169  bool foundGlobalTimeOffset = false;
170  const std::vector<const Property*>* properties = jos->getProperties( theName );
171  if ( 0 != properties ) {
172  // Iterate over the list to set the options
173  for ( std::vector<const Property*>::const_iterator itProp = properties->begin();
174  itProp != properties->end();
175  itProp++ ) {
176  const StringProperty* sp = dynamic_cast<const StringProperty*>(*itProp);
177  if ( 0 != sp ) {
178  if ( "Context" == (*itProp)->name() ) {
179  foundContext = true;
180  }
181  if ( "RootInTES" == (*itProp)->name() ) {
182  foundRootInTES = true;
183  }
184  if ( "GlobalTimeOffset" == (*itProp)->name() ) {
185  foundGlobalTimeOffset = true;
186  }
187  }
188  }
189  }
190  if ( !foundContext && "" != context() ) {
191  StringProperty contextProperty( "Context", context() );
192  jos->addPropertyToCatalogue( theName, contextProperty ).ignore();
193  addedContext = true;
194  }
195  if ( !foundRootInTES && "" != rootInTES() ) {
196  StringProperty rootInTESProperty( "RootInTES", rootInTES() );
197  jos->addPropertyToCatalogue( theName, rootInTESProperty ).ignore();
198  addedRootInTES = true;
199  }
200  if ( !foundGlobalTimeOffset && 0.0 != globalTimeOffset() ) {
201  DoubleProperty globalTimeOffsetProperty( "GlobalTimeOffset", globalTimeOffset() );
202  jos->addPropertyToCatalogue( theName, globalTimeOffsetProperty ).ignore();
203  addedGlobalTimeOffset = true;
204  }
205  }
206 
207  Algorithm *myAlg = 0;
208  result = createSubAlgorithm( theType, theName, myAlg );
209  // (MCl) this should prevent bug #35199... even if I didn't manage to
210  // reproduce it with a simple test.
211  if (result.isSuccess()) myIAlg = myAlg;
212  } else {
213  Algorithm *myAlg = dynamic_cast<Algorithm*>(myIAlg.get());
214  if (myAlg) {
215  subAlgorithms()->push_back(myAlg);
216  // when the algorithm is not created, the ref count is short by one, so we have to fix it.
217  myAlg->addRef();
218  }
219  }
220 
221  //== Remove the property, in case this is not a GaudiAlgorithm...
222  if ( addedContext ) {
223  jos->removePropertyFromCatalogue( theName, "Context" ).ignore();
224  addedContext = false;
225  }
226  if ( addedRootInTES ) {
227  jos->removePropertyFromCatalogue( theName, "RootInTES" ).ignore();
228  addedRootInTES = false;
229  }
230  if ( addedGlobalTimeOffset ) {
231  jos->removePropertyFromCatalogue( theName, "GlobalTimeOffset" ).ignore();
232  addedGlobalTimeOffset = false;
233  }
234 
235  // propagate the sub-algorithm into own state.
236  if ( result.isSuccess () &&
237  Gaudi::StateMachine::INITIALIZED <= FSMState() &&
238  myIAlg.isValid () &&
239  Gaudi::StateMachine::INITIALIZED > myIAlg->FSMState() )
240  {
241  StatusCode sc = myIAlg->sysInitialize() ;
242  if ( sc.isFailure() ) { result = sc ; }
243  }
244 
245  // propagate the sub-algorithm into own state.
246  if ( result.isSuccess () &&
247  Gaudi::StateMachine::RUNNING <= FSMState() &&
248  myIAlg.isValid () &&
249  Gaudi::StateMachine::RUNNING > myIAlg->FSMState() )
250  {
251  StatusCode sc = myIAlg->sysStart () ;
252  if ( sc.isFailure() ) { result = sc ; }
253  }
254 
255  //== Is it an Algorithm ? Strange test...
256  if ( result.isSuccess() ) {
257  // TODO: (MCl) it is possible to avoid the dynamic_cast in most of the
258  // cases by keeping the result of createSubAlgorithm.
259  Algorithm* myAlg = dynamic_cast<Algorithm*>(myIAlg.get());
260  if (myAlg!=0) {
261  // Note: The reference counting is kept by the system of sub-algorithms
262  m_entries.push_back( AlgorithmEntry( myAlg ) );
263  if (msgLevel(MSG::DEBUG)) debug () << "Added algorithm " << theName << endmsg;
264  } else {
265  warning() << theName << " is not an Algorithm - failed dynamic_cast"
266  << endmsg;
267  final = StatusCode::FAILURE;
268  }
269  } else {
270  warning() << "Unable to find or create " << theName << endmsg;
271  final = result;
272  }
273 
274  }
275 
276  release(appMgr).ignore();
277  release(jos).ignore();
278 
279  //== Print the list of algorithms
280  MsgStream& msg = info();
281  if ( m_modeOR ) msg << "OR ";
282  msg << "Member list: ";
283  std::vector<AlgorithmEntry>::iterator itE;
284  for ( itE = m_entries.begin(); m_entries.end() != itE; itE++ ) {
285  Algorithm* myAlg = (*itE).algorithm();
286  std::string myAlgType = System::typeinfoName( typeid( *myAlg) ) ;
287  if ( myAlg->name() == myAlgType ) {
288  msg << myAlg->name();
289  } else {
290  msg << myAlgType << "/" << myAlg->name();
291  }
292  if ( itE+1 != m_entries.end() ) msg << ", ";
293  }
294  if ( "" != context() ) msg << ", with context '" << context() << "'";
295  if ( "" != rootInTES() ) msg << ", with rootInTES '" << rootInTES() << "'";
296  if ( 0.0 != globalTimeOffset() ) msg << ", with globalTimeOffset " << globalTimeOffset();
297  msg << endmsg;
298 
299  return final;
300 
301 }
302 
303 //=========================================================================
304 // Interface for the Property manager
305 //=========================================================================
307 {
308  // no action for not-yet initialized sequencer
309  if ( Gaudi::StateMachine::INITIALIZED > FSMState() ) { return ; } // RETURN
310 
311  decodeNames().ignore();
312 
313  if ( !m_measureTime ) { return ; } // RETURN
314 
315  // add the entries into timer table:
316 
317  if ( 0 == m_timerTool )
318  { m_timerTool = tool<ISequencerTimerTool>( "SequencerTimerTool" ) ; }
319 
320  if ( m_timerTool->globalTiming() ) m_measureTime = true;
321 
324 
325  for ( std::vector<AlgorithmEntry>::iterator itE = m_entries.begin() ;
326  m_entries.end() != itE; ++itE )
327  {
328  itE->setTimer( m_timerTool->addTimer( itE->algorithm()->name() ) );
329  }
330 
332 
333 }
334 //=============================================================================
virtual SmartIF< IAlgorithm > & algorithm(const Gaudi::Utils::TypeNameString &typeName, const bool createIf=true)=0
Returns a smart pointer to a service.
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.
#define DECLARE_ALGORITHM_FACTORY(x)
Definition: Algorithm.h:946
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
virtual ~GaudiParallelizer()
Destructor.
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
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)
The IAlgManager is the interface implemented by the Algorithm Factory in the Application Manager to s...
Definition: IAlgManager.h:27
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:721
virtual void increaseIndent()=0
Increase the indentation of the name.
bool m_modeOR
Indicates that the OR is wanted instead of AND.
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.
MsgStream & msg() const
shortcut for the method msgStream(MSG::INFO)
virtual StatusCode finalize()
Algorithm finalization.
const std::string & name() const override
The identifying name of the algorithm object.
Definition: Algorithm.cpp:919
StringArrayProperty m_names
Input string, list of algorithms.
TYPE * get() const
Get interface pointer.
Definition: SmartIF.h:76
Helper class to parse a string of format "type/name".
Definition: TypeNameString.h:9
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
This class is used for returning status codes from appropriate routines.
Definition: StatusCode.h:26
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.
const TYPE & value() const
explicit conversion
Definition: Property.h:341
tbb::task_group m_task_group
TBB task group.
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
virtual StatusCode execute()
Algorithm execution.
bool isValid() const
Allow for check if smart pointer is valid.
Definition: SmartIF.h:62
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.
std::vector< AlgorithmEntry > m_entries
List of algorithms to process.
void membershipHandler(Property &theProp)
for asynchronous changes in the list of algorithms
virtual StatusCode addPropertyToCatalogue(const std::string &client, const Property &property)=0
Add a property into the JobOptions catalog.
tuple appMgr
Definition: IOTest.py:83
ISequencerTimerTool * m_timerTool
Pointer to the timer tool.
bool m_measureTime
Flag to measure time.
int m_timer
Timer number for the sequencer.
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)
unsigned short m_nthreads
Number of threads in the thread pool.
StatusCode sysInitialize() override
Initialization method invoked by the framework.
Definition: Algorithm.cpp:101
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.
void run(GaudiParallelizer &prlzr)
Thread task executor method to wrap an algorithm execution in.
virtual StatusCode initialize()
Algorithm initialization.
MSG::Level msgLevel() const
get the output level from the embedded MsgStream