The Gaudi Framework  v29r0 (ff2e7097)
PrecedenceSvc.cpp
Go to the documentation of this file.
1 #include "PrecedenceSvc.h"
2 #include "AlgResourcePool.h"
3 #include "EventSlot.h"
4 #include "PRGraphVisitors.h"
5 
8 
9 #define ON_DEBUG if ( msgLevel( MSG::DEBUG ) )
10 #define ON_VERBOSE if ( msgLevel( MSG::VERBOSE ) )
11 
13 
14 // ============================================================================
15 // Standard constructor, initializes variables
16 // ============================================================================
17 
18 PrecedenceSvc::PrecedenceSvc( const std::string& name, ISvcLocator* svcLoc ) : base_class( name, svcLoc ) {}
19 
20 // ============================================================================
21 // Initialization
22 // ============================================================================
24 {
25 
26  auto sc = Service::initialize(); // parent class must be initialized first
27  if ( sc.isFailure() ) {
28  fatal() << "Base class failed to initialize" << endmsg;
29  return sc;
30  }
31 
32  ON_DEBUG
33  {
34  // prepare a directory to dump precedence analysis files to.
36  if ( !boost::filesystem::create_directory( m_dumpDirName ) ) {
37  error() << "Could not create directory " << m_dumpDirName << "required "
38  "for task precedence tracing"
39  << endmsg;
40  return StatusCode::FAILURE;
41  }
42  }
43  }
44 
45  // Get the algo resource pool
46  m_algResourcePool = serviceLocator()->service( "AlgResourcePool" );
47  if ( !m_algResourcePool.isValid() ) {
48  fatal() << "Error retrieving AlgoResourcePool" << endmsg;
49  return StatusCode::FAILURE;
50  }
51 
52  info() << "Assembling CF and DF task precedence rules" << endmsg;
53 
54  ON_DEBUG debug() << "Assembling CF precedence realm:" << endmsg;
55  // create the root CF node
56  m_PRGraph.addHeadNode( "RootDecisionHub", true, false, true, true );
57  // assemble the CF rules
58  for ( const auto& ialgoPtr : m_algResourcePool->getTopAlgList() ) {
59  auto algorithm = dynamic_cast<Algorithm*>( ialgoPtr );
60  if ( !algorithm ) fatal() << "Conversion from IAlgorithm to Algorithm failed" << endmsg;
61  sc = assembleCFRules( algorithm, "RootDecisionHub" );
62  if ( sc.isFailure() ) {
63  fatal() << "Could not assemble the CF precedence realm" << endmsg;
64  return sc;
65  }
66  }
67 
68  if ( m_ignoreDFRules ) {
69  warning() << "Ignoring DF precedence rules, disabling all associated features" << endmsg;
70  return StatusCode::SUCCESS;
71  }
72 
73  ON_DEBUG debug() << "Assembling DF precedence realm:" << endmsg;
74  sc = m_PRGraph.initialize();
75  if ( sc.isFailure() ) {
76  fatal() << "Could not assemble the DF precedence realm" << endmsg;
77  return sc;
78  }
79 
80  // Rank algorithms if a prioritization rule is supplied
81  if ( m_mode == "PCE" ) {
83  m_PRGraph.rankAlgorithms( ranker );
84  } else if ( m_mode == "COD" ) {
86  m_PRGraph.rankAlgorithms( ranker );
87  } else if ( m_mode == "E" ) {
88  auto ranker = concurrency::RankerByEccentricity();
89  m_PRGraph.rankAlgorithms( ranker );
90  } else if ( m_mode == "T" ) {
91  auto ranker = concurrency::RankerByTiming();
92  m_PRGraph.rankAlgorithms( ranker );
93  } else if ( m_mode == "DRE" ) {
95  m_PRGraph.rankAlgorithms( ranker );
96  } else if ( !m_mode.empty() ) {
97  error() << "Requested prioritization rule '" << m_mode << "' is unknown" << endmsg;
98  return StatusCode::FAILURE;
99  }
100 
102 
103  if ( sc.isSuccess() ) info() << "PrecedenceSvc initialized successfully" << endmsg;
104 
105  return sc;
106 }
107 
108 // ============================================================================
109 StatusCode PrecedenceSvc::assembleCFRules( Algorithm* algo, const std::string& parentName, unsigned int recursionDepth )
110 {
112 
113  ++recursionDepth;
114 
115  bool isGaudiSequencer( false );
116  bool isAthSequencer( false );
117 
118  if ( algo->isSequence() ) {
119  if ( algo->hasProperty( "ShortCircuit" ) )
120  isGaudiSequencer = true;
121  else if ( algo->hasProperty( "StopOverride" ) )
122  isAthSequencer = true;
123  }
124 
125  std::vector<Algorithm*>* subAlgorithms = algo->subAlgorithms();
126  if ( // we only want to add basic algorithms -> have no subAlgs
127  // and exclude the case of empty sequencers
128  ( subAlgorithms->empty() && !( isGaudiSequencer || isAthSequencer ) ) ) {
129 
130  ON_DEBUG debug() << std::string( recursionDepth, ' ' ) << "Algorithm '" << algo->name() << "' discovered" << endmsg;
131  sc = m_PRGraph.addAlgorithmNode( algo, parentName, false, false );
132  return sc;
133  }
134 
135  // Recursively unroll
136  ON_DEBUG debug() << std::string( recursionDepth, ' ' ) << "Decision hub '" << algo->name() << "' discovered"
137  << endmsg;
138  bool modeOR = false;
139  bool allPass = false;
140  bool isLazy = false;
141  bool isSequential = false;
142 
143  if ( isGaudiSequencer ) {
144  modeOR = ( algo->getProperty( "ModeOR" ).toString() == "True" ) ? true : false;
145  allPass = ( algo->getProperty( "IgnoreFilterPassed" ).toString() == "True" ) ? true : false;
146  isLazy = ( algo->getProperty( "ShortCircuit" ).toString() == "True" ) ? true : false;
147  if ( allPass ) isLazy = false; // standard GaudiSequencer behavior on all pass is to execute everything
148  isSequential = ( algo->hasProperty( "Sequential" ) && ( algo->getProperty( "Sequential" ).toString() == "True" ) );
149  } else if ( isAthSequencer ) {
150  modeOR = ( algo->getProperty( "ModeOR" ).toString() == "True" ) ? true : false;
151  allPass = ( algo->getProperty( "IgnoreFilterPassed" ).toString() == "True" ) ? true : false;
152  isLazy = ( algo->getProperty( "StopOverride" ).toString() == "True" ) ? false : true;
153  isSequential = ( algo->hasProperty( "Sequential" ) && ( algo->getProperty( "Sequential" ).toString() == "True" ) );
154  }
155  sc = m_PRGraph.addDecisionHubNode( algo, parentName, !isSequential, isLazy, modeOR, allPass );
156  if ( sc.isFailure() ) {
157  error() << "Failed to add DecisionHub " << algo->name() << " to graph of precedence rules" << endmsg;
158  return sc;
159  }
160 
161  for ( Algorithm* subalgo : *subAlgorithms ) {
162  sc = assembleCFRules( subalgo, algo->name(), recursionDepth );
163  if ( sc.isFailure() ) {
164  error() << "Algorithm " << subalgo->name() << " could not be flattened" << endmsg;
165  return sc;
166  }
167  }
168  return sc;
169 }
170 
171 // ============================================================================
173 {
174 
175  bool ifTrace = false;
176  ON_DEBUG if ( m_dumpPrecTrace ) ifTrace = true; // enable precedence analysis
177 
178  if ( Cause::source::Task == cause.m_source ) {
179  ON_VERBOSE verbose() << "Triggering bottom-up traversal at node '" << cause.m_sourceName << "'" << endmsg;
180  auto visitor = concurrency::DecisionUpdater( slot, cause, ifTrace );
181  m_PRGraph.getAlgorithmNode( cause.m_sourceName )->accept( visitor );
182  } else {
183  ON_VERBOSE verbose() << "Triggering top-down traversal at the root node" << endmsg;
184  auto visitor = concurrency::Supervisor( slot, cause, ifTrace );
185  m_PRGraph.getHeadNode()->accept( visitor );
186  }
187 
188  ON_DEBUG
189  {
190  if ( m_dumpPrecTrace )
191  if ( CFRulesResolved( slot ) ) dumpPrecedenceTrace( slot );
192  if ( m_dumpPrecRules )
193  if ( CFRulesResolved( slot ) ) dumpPrecedenceRules( slot );
194  }
195 
196  return StatusCode::SUCCESS;
197 }
198 
199 // ============================================================================
201 {
202 
203  Cause cs = {Cause::source::Root, "RootDecisionHub"};
204  auto visitor = concurrency::RunSimulator( slot, cs );
205 
206  auto& nodeDecisions = slot.controlFlowState;
207 
208  std::vector<int> prevNodeDecisions;
209  int cntr = 0;
210  std::vector<int> counters;
211 
212  while ( !CFRulesResolved( slot ) ) {
213  cntr += 1;
214  int prevAlgosNum = visitor.m_nodesSucceeded;
215  debug() << " Proceeding with iteration #" << cntr << endmsg;
216  prevNodeDecisions = slot.controlFlowState;
217  m_PRGraph.getHeadNode()->accept( visitor );
218  if ( prevNodeDecisions == nodeDecisions ) {
219  error() << " No progress on iteration " << cntr << " detected, node decisions are:" << nodeDecisions << endmsg;
220  return StatusCode::FAILURE;
221  }
222  info() << " Iteration #" << cntr << " finished, total algorithms executed: " << visitor.m_nodesSucceeded
223  << endmsg;
224 
226  s << cntr << ", " << ( visitor.m_nodesSucceeded - prevAlgosNum ) << "\n";
227 
228  std::ofstream myfile;
229  myfile.open( "RunSimulation.csv", std::ios::app );
230  myfile << s.str();
231  myfile.close();
232 
233  if ( visitor.m_nodesSucceeded != prevAlgosNum ) counters.push_back( visitor.m_nodesSucceeded );
234  }
235 
236  info() << "Asymptotical concurrency speedup depth: " << (float)visitor.m_nodesSucceeded / (float)counters.size()
237  << endmsg;
238 
239  // Reset algorithm states and node decisions
240  slot.algsStates.reset();
241  nodeDecisions.assign( nodeDecisions.size(), -1 );
242 
243  return StatusCode::SUCCESS;
244 }
245 
246 // ============================================================================
248 {
249  return ( -1 != slot.controlFlowState[m_PRGraph.getHeadNode()->getNodeIndex()] ? true : false );
250 }
251 
252 // ============================================================================
254 {
255 
256  info() << std::endl << "==================== Control Flow Configuration ==================" << std::endl << std::endl;
258 }
259 // ============================================================================
261 {
262  info() << std::endl << "===================== Data Flow Configuration ====================" << std::endl;
263  info() << m_PRGraph.dumpDataFlow() << endmsg;
264 }
265 
266 // ============================================================================
268 {
269 
271  m_PRGraph.printState( ss, slot.algsStates, slot.controlFlowState, 0 );
272  return ss.str();
273 }
274 
275 // ============================================================================
277 {
278 
279  if ( !m_dumpPrecRules || !msgLevel( MSG::DEBUG ) ) {
280  info() << "No temporal and topological aspects of execution flow were traced. "
281  << "To get them traced, please set DumpPrecedenceRules "
282  << "property to True *and* put the whole application in DEBUG "
283  << "logging mode" << endmsg;
284  return;
285  }
286 
287  ON_DEBUG debug() << "Dumping temporal precedence rules" << endmsg;
288 
289  std::string fileName;
290  if ( m_dumpPrecRulesFile.empty() ) {
291  const auto& eventID = slot.eventContext->eventID();
292  fileName = "rules.evt-" + std::to_string( eventID.event_number() ) + "." + "run-" +
293  std::to_string( eventID.run_number() ) + ".graphml";
294  } else {
295  fileName = m_dumpPrecRulesFile;
296  }
297 
299  pth.append( fileName );
300 
301  m_PRGraph.dumpPrecRules( pth, slot );
302 }
303 
304 // ============================================================================
306 {
307 
308  if ( !m_dumpPrecTrace || !msgLevel( MSG::DEBUG ) ) {
309  info() << "Task precedence was not traced. To get it traced, please set "
310  << "DumpPrecedenceTrace property to True *and* put the "
311  << "whole application in DEBUG logging mode" << endmsg;
312  return;
313  }
314 
315  ON_DEBUG debug() << "Dumping temporal precedence trace" << endmsg;
316 
317  std::string fileName;
318  if ( m_dumpPrecTraceFile.empty() ) {
319  const auto& eventID = slot.eventContext->eventID();
320  fileName = "trace.evt-" + std::to_string( eventID.event_number() ) + "." + "run-" +
321  std::to_string( eventID.run_number() ) + ".graphml";
322  } else {
323  fileName = m_dumpPrecTraceFile;
324  }
325 
327  pth.append( fileName );
328 
329  m_PRGraph.dumpPrecTrace( pth );
330 }
331 
332 // ============================================================================
333 // Finalize
334 // ============================================================================
StatusCode getProperty(Gaudi::Details::PropertyBase *p) const override
get the property
Gaudi::Property< bool > m_dumpPrecTrace
Definition: PrecedenceSvc.h:85
concurrency::PrecedenceRulesGraph m_PRGraph
Graph of precedence rules.
Definition: PrecedenceSvc.h:77
StatusCode initialize() override
Definition: Service.cpp:64
void dumpPrecedenceRules(EventSlot &) override
Dump precedence rules (available only in DEBUG mode, and must be enabled with the corresponding servi...
T empty(T...args)
The ISvcLocator is the interface implemented by the Service Factory in the Application Manager to loc...
Definition: ISvcLocator.h:25
T open(T...args)
StatusCode addAlgorithmNode(Algorithm *daughterAlgo, const std::string &parentName, bool inverted, bool allPass)
Add algorithm node.
const std::string & name() const override
The identifying name of the algorithm object.
Definition: Algorithm.cpp:731
void dumpDataFlow() const override
StatusCode finalize() override
Definition: Service.cpp:174
MsgStream & info() const
shortcut for the method msgStream(MSG::INFO)
AlgsExecutionStates algsStates
Vector of algorithms states.
Definition: EventSlot.h:37
StatusCode assembleCFRules(Algorithm *, const std::string &, unsigned int recursionDepth=0)
EventContext * eventContext
Cache for the eventContext.
Definition: EventSlot.h:32
A service to resolve the task execution precedence.
Definition: PrecedenceSvc.h:21
bool hasProperty(const std::string &name) const override
Return true if we have a property with the given name.
void dumpPrecRules(const boost::filesystem::path &, const EventSlot &slot)
dump to file the precedence rules
T to_string(T...args)
MsgStream & verbose() const
shortcut for the method msgStream(MSG::VERBOSE)
T endl(T...args)
StatusCode addDecisionHubNode(Algorithm *daughterAlgo, const std::string &parentName, bool modeConcurrent, bool modePromptDecision, bool modeOR, bool allPass)
Add a node, which aggregates decisions of direct daughter nodes.
void printState(std::stringstream &output, AlgsExecutionStates &states, const std::vector< int > &node_decisions, const unsigned int &recursionLevel) const
Print a string representing the control flow state.
boost::filesystem::path m_dumpDirName
Precedence analysis facilities.
Definition: PrecedenceSvc.h:83
STL namespace.
void addHeadNode(const std::string &headName, bool modeConcurrent, bool modePromptDecision, bool modeOR, bool allPass)
Add a node, which has no parents.
#define ON_DEBUG
AlgorithmNode * getAlgorithmNode(const std::string &algoName) const
Get the AlgorithmNode from by algorithm name using graph index.
void rankAlgorithms(IGraphVisitor &ranker) const
Rank Algorithm nodes by the number of data outputs.
bool isFailure() const
Test for a status code of FAILURE.
Definition: StatusCode.h:86
Gaudi::Property< bool > m_ignoreDFRules
Scheduling strategy.
Definition: PrecedenceSvc.h:81
StatusCode iterate(EventSlot &, const Cause &) override
Infer the precedence effect caused by an execution flow event.
STL class.
Gaudi::Property< std::string > m_dumpPrecRulesFile
Definition: PrecedenceSvc.h:96
StatusCode service(const Gaudi::Utils::TypeNameString &name, T *&svc, bool createIf=true)
Templated method to access a service by name.
Definition: ISvcLocator.h:79
bool accept(IGraphVisitor &visitor) override
Visitor entry point.
StatusCode initialize()
Initialize graph.
T push_back(T...args)
MsgStream & error() const
shortcut for the method msgStream(MSG::ERROR)
STL class.
SmartIF< IAlgResourcePool > m_algResourcePool
A shortcut to the algorithm resource pool.
Definition: PrecedenceSvc.h:75
void dumpPrecTrace(const boost::filesystem::path &)
dump to file the precedence trace
virtual std::list< IAlgorithm * > getTopAlgList()=0
Get top list of algorithms.
MsgStream & warning() const
shortcut for the method msgStream(MSG::WARNING)
#define ON_VERBOSE
std::vector< int > controlFlowState
State of the control flow.
Definition: EventSlot.h:43
StatusCode finalize() override
Finalize.
This class is used for returning status codes from appropriate routines.
Definition: StatusCode.h:28
std::string dumpDataFlow() const
Print out all data origins and destinations, as reflected in the EF graph.
Gaudi::Property< std::string > m_mode
Scheduling strategy.
Definition: PrecedenceSvc.h:79
T str(T...args)
#define DECLARE_SERVICE_FACTORY(x)
Definition: Service.h:211
void dumpPrecedenceTrace(EventSlot &) override
Dump precedence trace (available only in DEBUG mode, and must be enabled with the corresponding servi...
bool CFRulesResolved(EventSlot &) const override
Check if the root CF decision is resolved.
StatusCode simulate(EventSlot &) const override
Simulate execution flow.
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
T size(T...args)
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
bool isSequence() const override
Are we a Sequence?
Definition: Algorithm.h:218
Gaudi::Property< bool > m_dumpPrecRules
Definition: PrecedenceSvc.h:93
Class representing the event slot.
Definition: EventSlot.h:11
string s
Definition: gaudirun.py:253
bool accept(IGraphVisitor &visitor) override
Visitor entry point.
Gaudi::Property< std::string > m_dumpPrecTraceFile
Definition: PrecedenceSvc.h:89
const std::string printState(EventSlot &) const override
const EventIDBase & eventID() const
Definition: EventContext.h:42
const unsigned int & getNodeIndex() const
Get node index.
MsgStream & fatal() const
shortcut for the method msgStream(MSG::FATAL)
void dumpControlFlow() const override
Dump precedence rules.
std::string dumpControlFlow() const
Print out control flow of Algorithms and Sequences.
MSG::Level msgLevel() const
get the output level from the embedded MsgStream
SmartIF< ISvcLocator > & serviceLocator() const override
Retrieve pointer to service locator.
Definition: Service.cpp:292
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition: MsgStream.h:209
std::string m_sourceName
StatusCode initialize() override
Initialize.
DecisionNode * getHeadNode() const
Get head node.