The Gaudi Framework  v30r2 (9eca68f7)
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 ) ) ) dumpPrecedenceTrace( slot );
185  if ( UNLIKELY( m_dumpPrecRules ) )
186  if ( UNLIKELY( CFRulesResolved( slot ) ) ) dumpPrecedenceRules( slot );
187 
188  return StatusCode::SUCCESS;
189 }
190 
191 // ============================================================================
193 {
194 
195  Cause cs = {Cause::source::Root, "RootDecisionHub"};
196  auto visitor = concurrency::RunSimulator( slot, cs );
197 
198  auto& nodeDecisions = slot.controlFlowState;
199 
200  std::vector<int> prevNodeDecisions;
201  int cntr = 0;
202  std::vector<int> counters;
203 
204  while ( !CFRulesResolved( slot ) ) {
205  cntr += 1;
206  int prevAlgosNum = visitor.m_nodesSucceeded;
207  ON_DEBUG debug() << " Proceeding with iteration #" << cntr << endmsg;
208  prevNodeDecisions = slot.controlFlowState;
209  m_PRGraph.getHeadNode()->accept( visitor );
210  if ( prevNodeDecisions == nodeDecisions ) {
211  error() << " No progress on iteration " << cntr << " detected, node decisions are:" << nodeDecisions << endmsg;
212  return StatusCode::FAILURE;
213  }
214  info() << " Iteration #" << cntr << " finished, total algorithms executed: " << visitor.m_nodesSucceeded
215  << endmsg;
216 
218  s << cntr << ", " << ( visitor.m_nodesSucceeded - prevAlgosNum ) << "\n";
219 
220  std::ofstream myfile;
221  myfile.open( "RunSimulation.csv", std::ios::app );
222  myfile << s.str();
223  myfile.close();
224 
225  if ( visitor.m_nodesSucceeded != prevAlgosNum ) counters.push_back( visitor.m_nodesSucceeded );
226  }
227 
228  info() << "Asymptotical intra-event speedup: " << (float)visitor.m_nodesSucceeded / (float)counters.size() << endmsg;
229 
230  // Reset algorithm states and node decisions
231  slot.algsStates.reset();
232  nodeDecisions.assign( nodeDecisions.size(), -1 );
233 
234  return StatusCode::SUCCESS;
235 }
236 
237 // ============================================================================
239 {
240  return ( -1 != slot.controlFlowState[m_PRGraph.getHeadNode()->getNodeIndex()] ? true : false );
241 }
242 
243 // ============================================================================
245 {
246 
247  info() << std::endl << "==================== Control Flow Configuration ==================" << std::endl << std::endl;
248  info() << m_PRGraph.dumpControlFlow() << endmsg;
249 }
250 // ============================================================================
252 {
253  info() << std::endl << "===================== Data Flow Configuration ====================" << std::endl;
254  info() << m_PRGraph.dumpDataFlow() << endmsg;
255 }
256 
257 // ============================================================================
259 {
260 
262  m_PRGraph.printState( ss, slot.algsStates, slot.controlFlowState, 0 );
263  return ss.str();
264 }
265 
266 // ============================================================================
268 {
269 
270  if ( !m_dumpPrecRules ) {
271  warning() << "To trace temporal and topological aspects of execution flow, "
272  << "set DumpPrecedenceRules property to True " << endmsg;
273  return;
274  }
275 
276  ON_DEBUG debug() << "Dumping temporal precedence rules" << endmsg;
277 
278  std::string fileName;
279  if ( m_dumpPrecRulesFile.empty() ) {
280  const auto& eventID = slot.eventContext->eventID();
281  fileName = "rules.evt-" + std::to_string( eventID.event_number() ) + "." + "run-" +
282  std::to_string( eventID.run_number() ) + ".graphml";
283  } else {
284  fileName = m_dumpPrecRulesFile;
285  }
286 
287  boost::filesystem::path pth{m_dumpDirName};
288  pth.append( fileName );
289 
290  m_PRGraph.dumpPrecRules( pth, slot );
291 }
292 
293 // ============================================================================
295 {
296 
297  if ( !m_dumpPrecTrace ) {
298  warning() << "To trace task precedence patterns, set DumpPrecedenceTrace "
299  << "property to True " << endmsg;
300  return;
301  }
302 
303  ON_DEBUG debug() << "Dumping temporal precedence trace" << endmsg;
304 
305  std::string fileName;
306  if ( m_dumpPrecTraceFile.empty() ) {
307  const auto& eventID = slot.eventContext->eventID();
308  fileName = "trace.evt-" + std::to_string( eventID.event_number() ) + "." + "run-" +
309  std::to_string( eventID.run_number() ) + ".graphml";
310  } else {
311  fileName = m_dumpPrecTraceFile;
312  }
313 
314  boost::filesystem::path pth{m_dumpDirName};
315  pth.append( fileName );
316 
317  m_PRGraph.dumpPrecTrace( pth );
318 }
319 
320 // ============================================================================
321 // Finalize
322 // ============================================================================
StatusCode getProperty(Gaudi::Details::PropertyBase *p) const override
get the property
#define UNLIKELY(x)
Definition: Kernel.h:128
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:746
void dumpDataFlow() const override
StatusCode finalize() override
Definition: Service.cpp:173
AlgsExecutionStates algsStates
Vector of algorithms states.
Definition: EventSlot.h:50
StatusCode assembleCFRules(Algorithm *, const std::string &, unsigned int recursionDepth=0)
EventContext * eventContext
Cache for the eventContext.
Definition: EventSlot.h:45
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
#define DECLARE_COMPONENT(type)
Definition: PluginService.h:33
StatusCode iterate(EventSlot &, const Cause &) override
Infer the precedence effect caused by an execution flow event.
STL class.
T push_back(T...args)
STL class.
#define ON_VERBOSE
std::vector< int > controlFlowState
State of the control flow.
Definition: EventSlot.h:54
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
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:127
const std::vector< Algorithm * > * subAlgorithms() const
List of sub-algorithms. Returns a pointer to a vector of (sub) Algorithms.
Definition: Algorithm.cpp:782
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:219
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