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