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