Loading [MathJax]/extensions/tex2jax.js
The Gaudi Framework  v31r0 (aeb156f0)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
PrecedenceSvc.cpp
Go to the documentation of this file.
1 #include "PrecedenceSvc.h"
2 #include "EventSlot.h"
3 #include "PRGraphVisitors.h"
4 
5 #include <Gaudi/Algorithm.h>
6 #include <Gaudi/Sequence.h>
7 
8 #define ON_DEBUG if ( msgLevel( MSG::DEBUG ) )
9 #define ON_VERBOSE if ( msgLevel( MSG::VERBOSE ) )
10 
12 
13 // ============================================================================
14 // Initialization
15 // ============================================================================
16 StatusCode PrecedenceSvc::initialize() {
17  using namespace concurrency;
18 
19  auto sc = Service::initialize(); // parent class must be initialized first
20  if ( sc.isFailure() ) {
21  fatal() << "Base class failed to initialize" << endmsg;
22  return sc;
23  }
24 
25  // prepare a directory to dump precedence analysis files to.
26  if ( m_dumpPrecTrace || m_dumpPrecRules ) {
27  if ( !boost::filesystem::create_directory( m_dumpDirName ) ) {
28  error() << "Could not create directory " << m_dumpDirName
29  << "required "
30  "for task precedence tracing"
31  << endmsg;
32  return StatusCode::FAILURE;
33  }
34  }
35 
36  if ( m_dumpPrecRules ) m_PRGraph.enableAnalysis();
37 
38  // Get the algo resource pool
39  m_algResourcePool = serviceLocator()->service( "AlgResourcePool" );
40  if ( !m_algResourcePool.isValid() ) {
41  fatal() << "Error retrieving AlgoResourcePool" << endmsg;
42  return StatusCode::FAILURE;
43  }
44 
45  info() << "Assembling CF and DF task precedence rules" << endmsg;
46 
47  ON_DEBUG debug() << "Assembling CF precedence realm:" << endmsg;
48  // create the root CF node
49  m_PRGraph.addHeadNode( "RootDecisionHub", Concurrent{true}, PromptDecision{false}, ModeOr{true}, AllPass{true},
50  Inverted{false} );
51  // assemble the CF rules
52  for ( const auto& ialgoPtr : m_algResourcePool->getTopAlgList() ) {
53  auto algorithm = dynamic_cast<Gaudi::Algorithm*>( ialgoPtr );
54  if ( !algorithm ) fatal() << "Conversion from IAlgorithm to Gaudi::Algorithm failed" << endmsg;
55  sc = assembleCFRules( algorithm, "RootDecisionHub" );
56  if ( sc.isFailure() ) {
57  fatal() << "Could not assemble the CF precedence realm" << endmsg;
58  return sc;
59  }
60  }
61 
62  if ( m_ignoreDFRules ) {
63  warning() << "Ignoring DF precedence rules, disabling all associated features" << endmsg;
64  return StatusCode::SUCCESS;
65  }
66 
67  ON_DEBUG debug() << "Assembling DF precedence realm:" << endmsg;
68  sc = m_PRGraph.initialize();
69  if ( sc.isFailure() ) {
70  fatal() << "Could not assemble the DF precedence realm" << endmsg;
71  return sc;
72  }
73 
74  // Rank algorithms if a prioritization rule is supplied
75  if ( m_mode == "PCE" ) {
77  m_PRGraph.rankAlgorithms( ranker );
78  } else if ( m_mode == "COD" ) {
80  m_PRGraph.rankAlgorithms( ranker );
81  } else if ( m_mode == "E" ) {
82  auto ranker = concurrency::RankerByEccentricity();
83  m_PRGraph.rankAlgorithms( ranker );
84  } else if ( m_mode == "T" ) {
85  auto ranker = concurrency::RankerByTiming();
86  m_PRGraph.rankAlgorithms( ranker );
87  } else if ( m_mode == "DRE" ) {
89  m_PRGraph.rankAlgorithms( ranker );
90  } else if ( !m_mode.empty() ) {
91  error() << "Requested prioritization rule '" << m_mode << "' is unknown" << endmsg;
92  return StatusCode::FAILURE;
93  }
94 
95  ON_DEBUG debug() << m_PRGraph.dumpDataFlow() << endmsg;
96 
97  if ( sc.isSuccess() ) info() << "PrecedenceSvc initialized successfully" << endmsg;
98 
99  return sc;
100 }
101 
102 // ============================================================================
104  unsigned int recursionDepth ) {
105  using namespace concurrency;
106 
108 
109  ++recursionDepth;
110 
111  bool isGaudiSequencer( false );
112  bool isAthSequencer( false );
113 
114  if ( !algo->isSequence() ) {
115  ON_DEBUG debug() << std::string( recursionDepth, ' ' ) << "Algorithm '" << algo->name() << "' discovered" << endmsg;
116  sc = m_PRGraph.addAlgorithmNode( algo, parentName, false, false );
117  return sc;
118  } else {
119  if ( algo->hasProperty( "ShortCircuit" ) )
120  isGaudiSequencer = true;
121  else if ( algo->hasProperty( "StopOverride" ) )
122  isAthSequencer = true;
123  }
124 
125  auto seq = dynamic_cast<Gaudi::Sequence*>( algo );
126  if ( seq == 0 ) {
127  error() << "Algorithm " << algo->name() << " has isSequence==true, but unable to dcast to Sequence" << endmsg;
128  return StatusCode::FAILURE;
129  }
130 
131  auto subAlgorithms = seq->subAlgorithms();
132 
133  // Recursively unroll
134  ON_DEBUG debug() << std::string( recursionDepth, ' ' ) << "Decision hub '" << algo->name() << "' discovered"
135  << endmsg;
136  bool modeOr = false;
137  bool allPass = false;
138  bool promptDecision = false;
139  bool isSequential = false;
140  bool isInverted = false;
141 
142  if ( isGaudiSequencer ) {
143  modeOr = ( algo->getProperty( "ModeOR" ).toString() == "True" );
144  allPass = ( algo->getProperty( "IgnoreFilterPassed" ).toString() == "True" );
145  promptDecision = ( algo->getProperty( "ShortCircuit" ).toString() == "True" );
146  isInverted = ( algo->getProperty( "Invert" ).toString() == "True" );
147  if ( allPass ) promptDecision = 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" );
151  allPass = ( algo->getProperty( "IgnoreFilterPassed" ).toString() == "True" );
152  promptDecision = ( algo->getProperty( "StopOverride" ).toString() == "False" );
153  isSequential = ( algo->hasProperty( "Sequential" ) && ( algo->getProperty( "Sequential" ).toString() == "True" ) );
154  }
155  sc = m_PRGraph.addDecisionHubNode( algo, parentName, Concurrent{!isSequential}, PromptDecision{promptDecision},
156  ModeOr{modeOr}, AllPass{allPass}, Inverted{isInverted} );
157  if ( sc.isFailure() ) {
158  error() << "Failed to add DecisionHub " << algo->name() << " to graph of precedence rules" << endmsg;
159  return sc;
160  }
161 
162  for ( auto subalgo : *subAlgorithms ) {
163  sc = assembleCFRules( subalgo, algo->name(), recursionDepth );
164  if ( sc.isFailure() ) {
165  error() << "Algorithm " << subalgo->name() << " could not be flattened" << endmsg;
166  return sc;
167  }
168  }
169  return sc;
170 }
171 
172 // ============================================================================
174 
175  if ( LIKELY( Cause::source::Task == cause.m_source ) ) {
176  ON_VERBOSE verbose() << "Triggering bottom-up traversal at node '" << cause.m_sourceName << "'" << endmsg;
177  auto visitor = concurrency::DecisionUpdater( slot, cause, m_dumpPrecTrace );
178  m_PRGraph.getAlgorithmNode( cause.m_sourceName )->accept( visitor );
179  } else {
180  ON_VERBOSE verbose() << "Triggering top-down traversal at the root node" << endmsg;
181  auto visitor = concurrency::Supervisor( slot, cause, m_dumpPrecTrace );
182  m_PRGraph.getHeadNode()->accept( visitor );
183  }
184 
185  if ( UNLIKELY( m_dumpPrecTrace ) )
186  if ( UNLIKELY( CFRulesResolved( slot.parentSlot ? *slot.parentSlot : slot ) ) )
187  dumpPrecedenceTrace( slot.parentSlot ? *slot.parentSlot : slot );
188 
189  if ( UNLIKELY( m_dumpPrecRules ) )
190  if ( UNLIKELY( CFRulesResolved( slot.parentSlot ? *slot.parentSlot : slot ) ) )
191  dumpPrecedenceRules( slot.parentSlot ? *slot.parentSlot : slot );
192 
193  return StatusCode::SUCCESS;
194 }
195 
196 // ============================================================================
198 
199  Cause cs = {Cause::source::Root, "RootDecisionHub"};
200  auto visitor = concurrency::RunSimulator( slot, cs );
201 
202  auto& nodeDecisions = slot.controlFlowState;
203 
204  std::vector<int> prevNodeDecisions;
205  int cntr = 0;
206  std::vector<int> counters;
207 
208  while ( !CFRulesResolved( slot ) ) {
209  cntr += 1;
210  int prevAlgosNum = visitor.m_nodesSucceeded;
211  ON_DEBUG debug() << " Proceeding with iteration #" << cntr << endmsg;
212  prevNodeDecisions = slot.controlFlowState;
213  m_PRGraph.getHeadNode()->accept( visitor );
214  if ( prevNodeDecisions == nodeDecisions ) {
215  error() << " No progress on iteration " << cntr << " detected, node decisions are:" << nodeDecisions << endmsg;
216  return StatusCode::FAILURE;
217  }
218  info() << " Iteration #" << cntr << " finished, total algorithms executed: " << visitor.m_nodesSucceeded
219  << endmsg;
220 
222  s << cntr << ", " << ( visitor.m_nodesSucceeded - prevAlgosNum ) << "\n";
223 
224  std::ofstream myfile;
225  myfile.open( "RunSimulation.csv", std::ios::app );
226  myfile << s.str();
227  myfile.close();
228 
229  if ( visitor.m_nodesSucceeded != prevAlgosNum ) counters.push_back( visitor.m_nodesSucceeded );
230  }
231 
232  info() << "Asymptotical intra-event speedup: " << (float)visitor.m_nodesSucceeded / (float)counters.size() << endmsg;
233 
234  // Reset algorithm states and node decisions
235  slot.algsStates.reset();
236  nodeDecisions.assign( nodeDecisions.size(), -1 );
237 
238  return StatusCode::SUCCESS;
239 }
240 
241 // ============================================================================
243  return ( -1 != slot.controlFlowState[m_PRGraph.getHeadNode()->getNodeIndex()] ? true : false );
244 }
245 
246 // ============================================================================
248 
249  info() << std::endl << "==================== Control Flow Configuration ==================" << std::endl << std::endl;
250  info() << m_PRGraph.dumpControlFlow() << endmsg;
251 }
252 // ============================================================================
254  info() << std::endl << "===================== Data Flow Configuration ====================" << std::endl;
255  info() << m_PRGraph.dumpDataFlow() << endmsg;
256 }
257 
258 // ============================================================================
260 
262  m_PRGraph.printState( ss, slot.algsStates, slot.controlFlowState, 0 );
263  return ss.str();
264 }
265 
266 // ============================================================================
268 
269  if ( !m_dumpPrecRules ) {
270  warning() << "To trace temporal and topological aspects of execution flow, "
271  << "set DumpPrecedenceRules property to True " << endmsg;
272  return;
273  }
274 
275  ON_DEBUG debug() << "Dumping temporal precedence rules" << endmsg;
276 
277  std::string fileName;
278  if ( m_dumpPrecRulesFile.empty() ) {
279  const auto& eventID = slot.eventContext->eventID();
280  fileName = "rules.evt-" + std::to_string( eventID.event_number() ) + "." + "run-" +
281  std::to_string( eventID.run_number() ) + ".graphml";
282  } else {
283  fileName = m_dumpPrecRulesFile;
284  }
285 
286  boost::filesystem::path pth{m_dumpDirName};
287  pth.append( fileName );
288 
289  m_PRGraph.dumpPrecRules( pth, slot );
290 }
291 
292 // ============================================================================
294 
295  if ( !m_dumpPrecTrace ) {
296  warning() << "To trace task precedence patterns, set DumpPrecedenceTrace "
297  << "property to True " << endmsg;
298  return;
299  }
300 
301  ON_DEBUG debug() << "Dumping temporal precedence trace" << endmsg;
302 
303  std::string fileName;
304  if ( m_dumpPrecTraceFile.empty() ) {
305  const auto& eventID = slot.eventContext->eventID();
306  fileName = "trace.evt-" + std::to_string( eventID.event_number() ) + "." + "run-" +
307  std::to_string( eventID.run_number() ) + ".graphml";
308  } else {
309  fileName = m_dumpPrecTraceFile;
310  }
311 
312  boost::filesystem::path pth{m_dumpDirName};
313  pth.append( fileName );
314 
315  m_PRGraph.dumpPrecTrace( pth );
316 }
317 
318 // ============================================================================
319 // Finalize
320 // ============================================================================
StatusCode getProperty(Gaudi::Details::PropertyBase *p) const override
get the property
#define UNLIKELY(x)
Definition: Kernel.h:89
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)
void dumpDataFlow() const override
StatusCode assembleCFRules(Gaudi::Algorithm *, const std::string &, unsigned int recursionDepth=0)
StatusCode finalize() override
Definition: Service.cpp:164
const std::string & name() const override
The identifying name of the algorithm object.
Definition: Algorithm.cpp:635
bool isSequence() const override
Are we a Sequence?
Definition: Algorithm.h:208
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.
T to_string(T...args)
T endl(T...args)
constexpr static const auto SUCCESS
Definition: StatusCode.h:85
std::vector< int > controlFlowState
State of the control flow.
Definition: EventSlot.h:77
#define ON_DEBUG
bool isFailure() const
Definition: StatusCode.h:130
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)
T push_back(T...args)
STL class.
#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
T str(T...args)
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.
Gaudi::tagged_bool< class Concurrent_tag > Concurrent
#define LIKELY(x)
Definition: Kernel.h:88
T size(T...args)
Gaudi::tagged_bool< class PromptDecision_tag > PromptDecision
Base class from which all concrete algorithm classes should be derived.
Definition: Algorithm.h:79
Gaudi::tagged_bool< class AllPass_tag > AllPass
string s
Definition: gaudirun.py:312
constexpr static const auto FAILURE
Definition: StatusCode.h:86
EventSlot * parentSlot
Pointer to parent slot (null for top level)
Definition: EventSlot.h:86
const std::string printState(EventSlot &) const override
const EventIDBase & eventID() const
Definition: EventContext.h:52
void dumpControlFlow() const override
Dump precedence rules.
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
AlgsExecutionStates algsStates
Vector of algorithms states.
Definition: EventSlot.h:75