The Gaudi Framework  v30r1 (5d4f4ae2)
PRGraphVisitors.cpp
Go to the documentation of this file.
1 #include "PRGraphVisitors.h"
2 #include "AlgsExecutionStates.h"
3 
5 #include "GaudiKernel/ICondSvc.h"
6 
7 namespace concurrency
8 {
9 
11 
12  //--------------------------------------------------------------------------
14  {
15 
16  if ( State::CONTROLREADY != m_slot->algsStates[node.getAlgoIndex()] ) return false;
17 
18  return true;
19  }
20 
21  //--------------------------------------------------------------------------
23  {
24 
25  bool result = true; // return true if this algorithm has no data inputs
26 
27  for ( auto dataNode : node.getInputDataNodes() ) {
28 
29  result = dataNode->accept( *this );
30 
31  // With ConditionNodes, one may decide NOT to break here so that associated
32  // ConditionAlgorithms are scheduled ASAP. This behavior can be made configurable
33  if ( !result ) break; // skip checking other inputs if this input was not produced yet
34  }
35 
36  if ( result ) {
37  m_slot->algsStates.updateState( node.getAlgoIndex(), State::DATAREADY ).ignore();
38 
39  // Inform parent slot if there is one
40  if ( m_slot->parentSlot ) {
42  }
43 
44  if ( m_trace ) {
45  auto sourceNode = ( m_cause.m_source == Cause::source::Task )
47  : nullptr;
48  node.m_graph->addEdgeToPrecTrace( sourceNode, &node );
49  }
50  }
51 
52  // return true only if an algorithm is promoted to DR
53  return result;
54  }
55 
56  //--------------------------------------------------------------------------
57  bool DataReadyPromoter::visitEnter( DataNode& ) const { return true; }
58 
59  //--------------------------------------------------------------------------
61  {
62  /* Implements 'observer' strategy, i.e., only check if producer of this DataNode
63  * has been already executed or not */
64 
65  auto const& producers = node.getProducers();
66  for ( auto algoNode : producers ) {
67  const auto& state = m_slot->algsStates[algoNode->getAlgoIndex()];
68  if ( State::EVTACCEPTED == state || State::EVTREJECTED == state ) {
69  return true; // skip checking other producers if one was found to be executed
70  }
71  }
72 
73  // Check parent slot if necessary
74  if ( m_slot->parentSlot ) {
75  for ( auto algoNode : producers ) {
76  const auto& state = m_slot->parentSlot->algsStates[algoNode->getAlgoIndex()];
77  if ( State::EVTACCEPTED == state || State::EVTREJECTED == state ) {
78  return true; // skip checking other producers if one was found to be executed
79  }
80  }
81  }
82 
83  // return true only if this DataNode is produced
84  return false;
85  }
86 
87  //--------------------------------------------------------------------------
89  {
90 
91  if ( node.m_condSvc->isValidID( *( m_slot->eventContext ), node.getPath() ) )
92  return false; // do not enter this ConditionNode if the condition has bee already loaded
93 
94  return true;
95  }
96 
97  //--------------------------------------------------------------------------
99  {
100  /* Implements 'requester' strategy, i.e., requests this ConditionNode to be loaded
101  * by its associated ConditionAlgorithm */
102 
103  auto promoter = Supervisor( *m_slot, m_cause, m_trace );
104 
105  for ( auto condAlg : node.getProducers() ) condAlg->accept( promoter );
106 
107  // this method is called if, and only if, this ConditionNode is not yet produced.
108  // thus, by definition, this ConditionNode is not yet available at this moment
109  return false;
110  }
111 
112  //--------------------------------------------------------------------------
114  {
115 
116  auto& states = m_slot->algsStates;
117  const State& state = states[node.getAlgoIndex()];
118  int decision = -1;
119 
120  if ( true == node.isOptimist() )
121  decision = 1;
122  else if ( State::EVTACCEPTED == state )
123  decision = !node.isLiar();
124  else if ( State::EVTREJECTED == state )
125  decision = node.isLiar();
126 
127  if ( -1 != decision ) {
128 
129  m_slot->controlFlowState[node.getNodeIndex()] = decision;
130 
131  auto promoter = DataReadyPromoter( *m_slot, m_cause, m_trace );
132  for ( const auto& output : node.getOutputDataNodes() )
133  for ( auto& consumer : output->getConsumers() ) consumer->accept( promoter );
134 
136  for ( auto& p : node.getParentDecisionHubs() ) p->accept( vis );
137 
138  return true; // return true only if the algorithm produced a decision
139  }
140 
141  return false;
142  }
143 
144  //---------------------------------------------------------------------------
146  {
147 
148  if ( m_slot->controlFlowState[node.getNodeIndex()] != -1 ) return false;
149  return true;
150  }
151 
152  //---------------------------------------------------------------------------
154  {
155 
156  bool foundNonResolvedChild = false;
157  bool foundNegativeChild = false;
158  bool foundPositiveChild = false;
159  int decision = -1;
160 
161  // If currently in a sub-slot, leave it if you've got to the exit
163 
164  // If children are in sub-slots, loop over all
165  auto searchResult = m_slot->subSlotsByNode.find( node.getNodeName() );
166  if ( searchResult != m_slot->subSlotsByNode.end() ) {
167  bool breakout = false;
168  for ( unsigned int slotIndex : searchResult->second ) {
169 
170  // Enter the sub-slot
171  m_slot = &( m_slot->allSubSlots[slotIndex] );
172 
173  for ( auto child : node.getDaughters() ) {
174 
175  int& childDecision = m_slot->controlFlowState[child->getNodeIndex()];
176 
177  if ( childDecision == -1 )
178  foundNonResolvedChild = true;
179  else if ( childDecision == 1 )
180  foundPositiveChild = true;
181  else
182  foundNegativeChild = true;
183 
184  if ( node.m_modePromptDecision ) {
185  if ( node.m_modeOR && foundPositiveChild ) {
186  decision = 1;
187  breakout = true;
188  break;
189  } else if ( !node.m_modeOR && foundNegativeChild ) {
190  decision = 0;
191  breakout = true;
192  break;
193  }
194  } else {
195  if ( foundNonResolvedChild ) {
196  breakout = true;
197  break;
198  }
199  }
200  }
201 
202  // Leave the sub-slot
204  if ( breakout ) break;
205  }
206  } else {
207  for ( auto child : node.getDaughters() ) {
208  int& childDecision = m_slot->controlFlowState[child->getNodeIndex()];
209 
210  if ( childDecision == -1 )
211  foundNonResolvedChild = true;
212  else if ( childDecision == 1 )
213  foundPositiveChild = true;
214  else
215  foundNegativeChild = true;
216 
217  if ( node.m_modePromptDecision ) {
218  if ( node.m_modeOR && foundPositiveChild ) {
219  decision = 1;
220  break;
221  } else if ( !node.m_modeOR && foundNegativeChild ) {
222  decision = 0;
223  break;
224  }
225  } else {
226  if ( foundNonResolvedChild ) break;
227  }
228  }
229  } // end monitoring children
230 
231  if ( !foundNonResolvedChild && decision == -1 ) {
232  if ( node.m_modeOR ) { // OR
233  if ( foundPositiveChild )
234  decision = 1;
235  else
236  decision = 0;
237  } else { // AND
238  if ( foundNegativeChild )
239  decision = 0;
240  else
241  decision = 1;
242  }
243  }
244 
245  if ( node.m_inverted && decision == 1 )
246  decision = 0;
247  else if ( node.m_inverted && decision == 0 )
248  decision = 1;
249 
250  if ( node.m_allPass && !foundNonResolvedChild ) decision = 1;
251 
252  if ( decision != -1 ) {
253  m_slot->controlFlowState[node.getNodeIndex()] = decision;
254  return true;
255  }
256 
257  // if no decision can be made yet, request further information downwards
258  // Enter subslots for children if needed
259  if ( searchResult != m_slot->subSlotsByNode.end() ) {
260  for ( unsigned int slotIndex : searchResult->second ) {
261 
262  // Enter sub-slot
263  m_slot = &( m_slot->allSubSlots[slotIndex] );
264 
265  for ( auto child : node.getDaughters() ) {
266  bool result = child->accept( *this );
267  if ( !node.m_modeConcurrent )
268  if ( result ) break; // stop on first unresolved child if its decision hub is sequential
269  }
270 
271  // Leave sub-slot
273  }
274  } else {
275  for ( auto child : node.getDaughters() ) {
276  bool result = child->accept( *this );
277  if ( !node.m_modeConcurrent )
278  if ( result ) break; // stop on first unresolved child if its decision hub is sequential
279  }
280  }
281 
282  return false;
283  }
284 
285  //---------------------------------------------------------------------------
287  {
288 
289  if ( m_slot->controlFlowState[node.getNodeIndex()] != -1 ) return false;
290  return true;
291  }
292 
293  //--------------------------------------------------------------------------
295  {
296 
297  bool result = false;
298 
299  auto& states = m_slot->algsStates;
300  auto& state = states[node.getAlgoIndex()];
301 
302  // Promote with INITIAL->CR
303  if ( State::INITIAL == state ) states.updateState( node.getAlgoIndex(), State::CONTROLREADY ).ignore();
304 
305  // Try to promote with CR->DR
306  if ( State::CONTROLREADY == state ) {
307  auto promoter = DataReadyPromoter( *m_slot, m_cause, m_trace );
308  result = promoter.visit( node );
309  } else {
310  result = true;
311  }
312 
313  // return true only when an algorithm is not lower than DR in its FSM
314  // i.e., the visitor has done everything it could with this algorithm
315  return result;
316  }
317 
318  //--------------------------------------------------------------------------
320  {
321 
322  auto& products = node.getOutputDataNodes();
323  float rank = 0;
324 
325  for ( auto p : products ) rank += p->getConsumers().size();
326 
327  node.setRank( rank );
328  /*std::stringstream s;
329  s << node.getNodeName() << ", " << rank << "\n";
330  std::ofstream myfile;
331  myfile.open("AlgoRank.csv", std::ios::app);
332  myfile << s.str();
333  myfile.close();*/
334 
335  return true;
336  }
337 
338  //--------------------------------------------------------------------------
340  {
341 
342  std::ifstream myfile;
343  myfile.open( "InputExecutionPlan.graphml", std::ios::in );
344 
345  precedence::PrecTrace execPlan;
346 
348  using boost::get;
349 
350  boost::dynamic_properties dp;
351  dp.property( "name", get( &AlgoTraceProps::m_name, execPlan ) );
352  dp.property( "index", get( &AlgoTraceProps::m_index, execPlan ) );
353  dp.property( "dataRank", get( &AlgoTraceProps::m_rank, execPlan ) );
354  dp.property( "runtime", get( &AlgoTraceProps::m_runtime, execPlan ) );
355 
356  boost::read_graphml( myfile, execPlan, dp );
357 
358  typedef boost::graph_traits<precedence::PrecTrace>::vertex_iterator itV;
360 
361  for ( vp = boost::vertices( execPlan ); vp.first != vp.second; ++vp.first ) {
362  precedence::AlgoTraceVertex v = *vp.first;
363  auto index = get( &AlgoTraceProps::m_name, execPlan );
364  if ( index[v] == node.getNodeName() ) {
365  runThroughAdjacents( v, execPlan );
366  float rank = m_nodesSucceeded;
367  node.setRank( rank );
368  reset();
369  // std::cout << "Rank of " << index[v] << " is " << rank << std::endl;
370  }
371  }
372 
373  return true;
374  }
375 
376  //--------------------------------------------------------------------------
378  boost::graph_traits<precedence::PrecTrace>::vertex_descriptor vertex, precedence::PrecTrace graph )
379  {
380  typename boost::graph_traits<precedence::PrecTrace>::adjacency_iterator itVB;
381  typename boost::graph_traits<precedence::PrecTrace>::adjacency_iterator itVE;
382 
383  for ( boost::tie( itVB, itVE ) = adjacent_vertices( vertex, graph ); itVB != itVE; ++itVB ) {
384  m_nodesSucceeded += 1;
385  runThroughAdjacents( *itVB, graph );
386  }
387  }
388 
389  //--------------------------------------------------------------------------
391  {
392 
393  std::ifstream myfile;
394  myfile.open( "InputExecutionPlan.graphml", std::ios::in );
395 
396  precedence::PrecTrace execPlan;
398  using boost::get;
399 
400  boost::dynamic_properties dp;
401  dp.property( "name", get( &AlgoTraceProps::m_name, execPlan ) );
402  dp.property( "index", get( &AlgoTraceProps::m_index, execPlan ) );
403  dp.property( "dataRank", get( &AlgoTraceProps::m_rank, execPlan ) );
404  dp.property( "runtime", get( &AlgoTraceProps::m_runtime, execPlan ) );
405 
406  boost::read_graphml( myfile, execPlan, dp );
407 
408  typedef boost::graph_traits<precedence::PrecTrace>::vertex_iterator itV;
410 
411  for ( vp = boost::vertices( execPlan ); vp.first != vp.second; ++vp.first ) {
412  precedence::AlgoTraceVertex v = *vp.first;
413  auto index = get( &AlgoTraceProps::m_name, execPlan );
414  if ( index[v] == node.getNodeName() ) {
415  auto index_runtime = get( &AlgoTraceProps::m_runtime, execPlan );
416  float rank = index_runtime[v];
417  node.setRank( rank );
418  // std::cout << "Rank of " << index[v] << " is " << rank << std::endl;
419  }
420  }
421  return true;
422  }
423 
424  //--------------------------------------------------------------------------
426  {
427 
428  std::ifstream myfile;
429  myfile.open( "Eccentricity.graphml", std::ios::in );
430 
431  precedence::PrecTrace execPlan;
432 
433  boost::dynamic_properties dp;
434  using boost::get;
435 
436  dp.property( "name", get( &precedence::AlgoTraceProps::m_name, execPlan ) );
437  dp.property( "Eccentricity", get( &precedence::AlgoTraceProps::m_eccentricity, execPlan ) );
438 
439  boost::read_graphml( myfile, execPlan, dp );
440 
441  typedef boost::graph_traits<precedence::PrecTrace>::vertex_iterator itV;
443 
444  for ( vp = boost::vertices( execPlan ); vp.first != vp.second; ++vp.first ) {
445  precedence::AlgoTraceVertex v = *vp.first;
446  auto index = get( &precedence::AlgoTraceProps::m_name, execPlan );
447  if ( index[v] == node.getNodeName() ) {
448  auto index_eccentricity = get( &precedence::AlgoTraceProps::m_eccentricity, execPlan );
449  float rank = index_eccentricity[v];
450  node.setRank( rank );
451  // std::cout << "Rank of " << index[v] << " is " << rank << std::endl;
452  }
453  }
454  return true;
455  }
456 
457  //--------------------------------------------------------------------------
459  {
460 
461  // Find eccentricity of the node (only within the data realm of the execution flow graph)
462  recursiveVisit( node );
463 
464  float rank = m_maxKnownDepth;
465  node.setRank( rank );
466 
467  // Reset visitor for next nodes, if any
468  reset();
469 
470  return true;
471  }
472 
473  //--------------------------------------------------------------------------
475  {
476 
477  m_currentDepth += 1;
478 
479  auto& products = node.getOutputDataNodes();
480 
481  if ( products.empty() )
482  if ( ( m_currentDepth - 1 ) > m_maxKnownDepth ) m_maxKnownDepth = m_currentDepth - 1;
483 
484  for ( auto p : products )
485  for ( auto algoNode : p->getConsumers() ) recursiveVisit( *algoNode );
486 
487  m_currentDepth -= 1;
488  }
489 
490  //---------------------------------------------------------------------------
492  {
493 
494  if ( m_slot->controlFlowState[node.getNodeIndex()] != 1 ) return true;
495  return false;
496  }
497 
498  //---------------------------------------------------------------------------
500  {
501 
502  // std::cout << "1-st level Decision: " << node.getNodeName() << std::endl;
503  bool allChildDecisionsResolved = true;
504  for ( auto child : node.getDaughters() ) {
505  int& childDecision = m_slot->controlFlowState[child->getNodeIndex()];
506 
507  if ( childDecision == 1 && node.m_modeOR && node.m_modePromptDecision ) {
508  m_slot->controlFlowState[node.getNodeIndex()] = 1;
509  return true;
510  }
511 
512  if ( childDecision == -1 ) {
513  allChildDecisionsResolved = false;
514  }
515  }
516 
517  if ( allChildDecisionsResolved ) m_slot->controlFlowState[node.getNodeIndex()] = 1;
518 
519  return allChildDecisionsResolved;
520  }
521 
522  //---------------------------------------------------------------------------
524  {
525 
526  if ( m_slot->controlFlowState[node.getNodeIndex()] != 1 ) return true;
527  return false;
528  }
529 
530  //--------------------------------------------------------------------------
532  {
533 
534  auto& states = m_slot->algsStates;
535  int& decision = m_slot->controlFlowState[node.getNodeIndex()];
536 
537  auto dataPromoter = DataReadyPromoter( *m_slot, m_cause );
538 
539  if ( State::INITIAL == states[node.getAlgoIndex()] ) {
540  states.updateState( node.getAlgoIndex(), State::CONTROLREADY );
541  if ( dataPromoter.visit( node ) ) {
542  states.updateState( node.getAlgoIndex(), State::SCHEDULED );
543  states.updateState( node.getAlgoIndex(), State::EVTACCEPTED );
544  decision = 1;
545  ++m_nodesSucceeded;
546  // std::cout << "Algorithm decided: " << node.getNodeName() << std::endl;
547  return true;
548  }
549  } else if ( State::CONTROLREADY == states[node.getAlgoIndex()] && dataPromoter.visit( node ) ) {
550  states.updateState( node.getAlgoIndex(), State::SCHEDULED );
551  states.updateState( node.getAlgoIndex(), State::EVTACCEPTED );
552  decision = 1;
553  ++m_nodesSucceeded;
554  // std::cout << "Algorithm decided: " << node.getNodeName() << std::endl;
555  return true;
556  }
557 
558  return false;
559  }
560 }
const unsigned int & getAlgoIndex() const
Get algorithm index.
T open(T...args)
bool visit(AlgorithmNode &) override
boost::graph_traits< PrecTrace >::vertex_descriptor AlgoTraceVertex
const std::vector< DataNode * > & getInputDataNodes() const
Get all consumer nodes.
bool isOptimist() const
Check if positive control flow decision is enforced.
AlgsExecutionStates algsStates
Vector of algorithms states.
Definition: EventSlot.h:50
EventContext * eventContext
Cache for the eventContext.
Definition: EventSlot.h:45
void setRank(float &rank)
Set Algorithm rank.
bool visit(AlgorithmNode &) override
void recursiveVisit(AlgorithmNode &)
Depth-first node parser to calculate node eccentricity (only within the data realm of the precedence ...
const std::vector< DataNode * > & getOutputDataNodes() const
Get all supplier nodes.
T end(T...args)
AlgorithmNode * getAlgorithmNode(const std::string &algoName) const
Get the AlgorithmNode from by algorithm name using graph index.
bool m_allPass
Whether always passing regardless of daughter results.
std::string entryPoint
Name of the node this slot is attached to ("" for top level)
Definition: EventSlot.h:58
const std::vector< DecisionNode * > & getParentDecisionHubs() const
Get all parent decision hubs.
bool visit(DecisionNode &) override
bool visitEnter(AlgorithmNode &) const override
bool visit(AlgorithmNode &) override
bool visitEnter(DecisionNode &) const override
bool m_modeOR
Whether acting as "and" (false) or "or" node (true)
T push_back(T...args)
bool visit(AlgorithmNode &) override
PrecedenceRulesGraph * m_graph
bool visitEnter(DecisionNode &) const override
std::vector< int > controlFlowState
State of the control flow.
Definition: EventSlot.h:54
DataReadyPromoter(EventSlot &slot, const Cause &cause, bool ifTrace=false)
Constructor.
const DataObjID & getPath()
std::vector< std::pair< EventContext *, int > > subSlotAlgsReady
Quick lookup for data-ready algorithms in sub-slots (top level only)
Definition: EventSlot.h:62
const std::vector< ControlFlowNode * > & getDaughters() const
Get children nodes.
bool visit(AlgorithmNode &) override
void runThroughAdjacents(boost::graph_traits< precedence::PrecTrace >::vertex_descriptor, precedence::PrecTrace)
EventSlot * parentSlot
Pointer to parent slot (null for top level)
Definition: EventSlot.h:60
boost::adjacency_list< boost::vecS, boost::vecS, boost::bidirectionalS, AlgoTraceProps > PrecTrace
T make_pair(T...args)
virtual bool isValidID(const EventContext &ctx, const DataObjID &id) const =0
check to see if a specific condition object ID is valid for this event
State
Execution states of the algorithms.
std::map< std::string, std::vector< unsigned int > > subSlotsByNode
Listing of sub-slots by the node (name) they are attached to.
Definition: EventSlot.h:56
bool m_modePromptDecision
Whether to evaluate the hub decision ASA its child decisions allow to do that.
void addEdgeToPrecTrace(const AlgorithmNode *u, const AlgorithmNode *v)
set cause-effect connection between two algorithms in the precedence trace
bool visit(DecisionNode &) override
T find(T...args)
std::vector< EventSlot > allSubSlots
Actual sub-slot instances.
Definition: EventSlot.h:66
bool m_modeConcurrent
Whether all daughters will be evaluated concurrently or sequentially.
bool visit(AlgorithmNode &) override
bool m_inverted
Whether the selection result is negated or not.
bool isLiar() const
Check if control flow logic is always inverted.
bool visit(AlgorithmNode &) override
const std::string & getNodeName() const
Get node name.
const unsigned int & getNodeIndex() const
Get node index.
STL class.
std::string m_sourceName
const std::vector< AlgorithmNode * > & getProducers() const
Get all data object producers.
AlgsExecutionStates::State State
StatusCode updateState(unsigned int iAlgo, State newState)