The Gaudi Framework  v30r2 (9eca68f7)
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 #include <queue>
8 
9 namespace concurrency
10 {
11 
13 
14  //--------------------------------------------------------------------------
16  {
17 
18  if ( State::CONTROLREADY != m_slot->algsStates[node.getAlgoIndex()] ) return false;
19 
20  return true;
21  }
22 
23  //--------------------------------------------------------------------------
25  {
26 
27  bool result = true; // return true if this algorithm has no data inputs
28 
29  for ( auto dataNode : node.getInputDataNodes() ) {
30 
31  result = dataNode->accept( *this );
32 
33  // With ConditionNodes, one may decide NOT to break here so that associated
34  // ConditionAlgorithms are scheduled ASAP. This behavior can be made configurable
35  if ( !result ) break; // skip checking other inputs if this input was not produced yet
36  }
37 
38  if ( result ) {
39  m_slot->algsStates.updateState( node.getAlgoIndex(), State::DATAREADY ).ignore();
40 
41  // Inform parent slot if there is one
42  if ( m_slot->parentSlot ) {
44  }
45 
46  if ( m_trace ) {
47  auto sourceNode = ( m_cause.m_source == Cause::source::Task )
49  : nullptr;
50  node.m_graph->addEdgeToPrecTrace( sourceNode, &node );
51  }
52  }
53 
54  // return true only if an algorithm is promoted to DR
55  return result;
56  }
57 
58  //--------------------------------------------------------------------------
59  bool DataReadyPromoter::visitEnter( DataNode& ) const { return true; }
60 
61  //--------------------------------------------------------------------------
63  {
64  /* Implements 'observer' strategy, i.e., only check if producer of this DataNode
65  * has been already executed or not */
66 
67  auto const& producers = node.getProducers();
68  for ( auto algoNode : producers ) {
69  const auto& state = m_slot->algsStates[algoNode->getAlgoIndex()];
70  if ( State::EVTACCEPTED == state || State::EVTREJECTED == state ) {
71  return true; // skip checking other producers if one was found to be executed
72  }
73  }
74 
75  // Check parent slot if necessary
76  if ( m_slot->parentSlot ) {
77  for ( auto algoNode : producers ) {
78  const auto& state = m_slot->parentSlot->algsStates[algoNode->getAlgoIndex()];
79  if ( State::EVTACCEPTED == state || State::EVTREJECTED == state ) {
80  return true; // skip checking other producers if one was found to be executed
81  }
82  }
83  }
84 
85  // return true only if this DataNode is produced
86  return false;
87  }
88 
89  //--------------------------------------------------------------------------
91  {
92 
93  if ( node.m_condSvc->isValidID( *( m_slot->eventContext ), node.getPath() ) )
94  return false; // do not enter this ConditionNode if the condition has bee already loaded
95 
96  return true;
97  }
98 
99  //--------------------------------------------------------------------------
101  {
102  /* Implements 'requester' strategy, i.e., requests this ConditionNode to be loaded
103  * by its associated ConditionAlgorithm */
104 
105  auto promoter = Supervisor( *m_slot, m_cause, m_trace );
106 
107  for ( auto condAlg : node.getProducers() ) condAlg->accept( promoter );
108 
109  // this method is called if, and only if, this ConditionNode is not yet produced.
110  // thus, by definition, this ConditionNode is not yet available at this moment
111  return false;
112  }
113 
114  //--------------------------------------------------------------------------
116  {
117 
118  auto& states = m_slot->algsStates;
119  const State& state = states[node.getAlgoIndex()];
120  int decision = -1;
121 
122  if ( true == node.isOptimist() )
123  decision = 1;
124  else if ( State::EVTACCEPTED == state )
125  decision = !node.isLiar();
126  else if ( State::EVTREJECTED == state )
127  decision = node.isLiar();
128 
129  if ( -1 != decision ) {
130 
131  m_slot->controlFlowState[node.getNodeIndex()] = decision;
132 
133  auto promoter = DataReadyPromoter( *m_slot, m_cause, m_trace );
134  for ( const auto& output : node.getOutputDataNodes() )
135  for ( auto& consumer : output->getConsumers() ) consumer->accept( promoter );
136 
138  for ( auto& p : node.getParentDecisionHubs() ) p->accept( vis );
139 
140  return true; // return true only if the algorithm produced a decision
141  }
142 
143  return false;
144  }
145 
146  //---------------------------------------------------------------------------
148  {
149  // Protect against graph traversal escaping from sub-slots
150  if ( m_slot->parentSlot ) {
151  // Examine the ancestry of this node, looking for sub-slot entry point
152  bool canFindExit = false;
153  std::queue<DecisionNode*> allAncestors;
154  allAncestors.push( &node );
155  while ( allAncestors.size() ) {
156 
157  DecisionNode* thisAncestor = allAncestors.front();
158  allAncestors.pop();
159 
160  if ( thisAncestor->getNodeName() == m_slot->entryPoint ) {
161 
162  // This ancestor is the sub-slot exit
163  canFindExit = true;
164  break;
165 
166  } else {
167 
168  // Go further up the node ancestry
169  for ( auto& evenOlder : thisAncestor->m_parents ) {
170 
171  allAncestors.push( evenOlder );
172  }
173  }
174  }
175 
176  // If the sub-slot entry point is not in this node's ancestry, don't visit the node
177  if ( !canFindExit ) return false;
178  }
179 
180  if ( m_slot->controlFlowState[node.getNodeIndex()] != -1 ) return false;
181  return true;
182  }
183 
184  //---------------------------------------------------------------------------
186  {
187 
188  bool foundNonResolvedChild = false;
189  bool foundNegativeChild = false;
190  bool foundPositiveChild = false;
191  int decision = -1;
192 
193  // Leave a sub-slot if this is the exit node
194  EventSlot* oldSlot = nullptr;
195  if ( m_slot->parentSlot && m_slot->entryPoint == node.getNodeName() ) {
196  oldSlot = m_slot;
198  }
199 
200  // If children are in sub-slots, loop over all
201  auto searchResult = m_slot->subSlotsByNode.find( node.getNodeName() );
202  if ( searchResult != m_slot->subSlotsByNode.end() ) {
203  bool breakout = false;
204  for ( unsigned int slotIndex : searchResult->second ) {
205 
206  // Enter the sub-slot
207  m_slot = &( m_slot->allSubSlots[slotIndex] );
208 
209  for ( auto child : node.getDaughters() ) {
210 
211  int& childDecision = m_slot->controlFlowState[child->getNodeIndex()];
212 
213  if ( childDecision == -1 )
214  foundNonResolvedChild = true;
215  else if ( childDecision == 1 )
216  foundPositiveChild = true;
217  else
218  foundNegativeChild = true;
219 
220  if ( node.m_modePromptDecision ) {
221  if ( node.m_modeOR && foundPositiveChild ) {
222  decision = 1;
223  breakout = true;
224  break;
225  } else if ( !node.m_modeOR && foundNegativeChild ) {
226  decision = 0;
227  breakout = true;
228  break;
229  }
230  } else {
231  if ( foundNonResolvedChild ) {
232  breakout = true;
233  break;
234  }
235  }
236  }
237 
238  // Leave the sub-slot
240  if ( breakout ) break;
241  }
242  } else {
243  for ( auto child : node.getDaughters() ) {
244  int& childDecision = m_slot->controlFlowState[child->getNodeIndex()];
245 
246  if ( childDecision == -1 )
247  foundNonResolvedChild = true;
248  else if ( childDecision == 1 )
249  foundPositiveChild = true;
250  else
251  foundNegativeChild = true;
252 
253  if ( node.m_modePromptDecision ) {
254  if ( node.m_modeOR && foundPositiveChild ) {
255  decision = 1;
256  break;
257  } else if ( !node.m_modeOR && foundNegativeChild ) {
258  decision = 0;
259  break;
260  }
261  } else {
262  if ( foundNonResolvedChild ) break;
263  }
264  }
265  } // end monitoring children
266 
267  if ( !foundNonResolvedChild && decision == -1 ) {
268  if ( node.m_modeOR ) { // OR
269  if ( foundPositiveChild )
270  decision = 1;
271  else
272  decision = 0;
273  } else { // AND
274  if ( foundNegativeChild )
275  decision = 0;
276  else
277  decision = 1;
278  }
279  }
280 
281  if ( node.m_inverted && decision == 1 )
282  decision = 0;
283  else if ( node.m_inverted && decision == 0 )
284  decision = 1;
285 
286  if ( node.m_allPass && !foundNonResolvedChild ) decision = 1;
287 
288  if ( decision != -1 ) {
289  m_slot->controlFlowState[node.getNodeIndex()] = decision;
290 
291  // if a decision was made for this node, propagate the result upwards
292  for ( auto parent : node.m_parents ) {
293  parent->accept( *this );
294  }
295 
296  if ( oldSlot ) m_slot = oldSlot;
297  return true;
298  }
299 
300  // if no decision can be made yet, request further information downwards
301  // Enter subslots for children if needed
302  if ( searchResult != m_slot->subSlotsByNode.end() ) {
303  for ( unsigned int slotIndex : searchResult->second ) {
304 
305  // Enter sub-slot
306  m_slot = &( m_slot->allSubSlots[slotIndex] );
307 
308  for ( auto child : node.getDaughters() ) {
309  bool result = child->accept( *this );
310  if ( !node.m_modeConcurrent )
311  if ( result ) break; // stop on first unresolved child if its decision hub is sequential
312  }
313 
314  // Leave sub-slot
316  }
317  } else {
318  for ( auto child : node.getDaughters() ) {
319  bool result = child->accept( *this );
320  if ( !node.m_modeConcurrent )
321  if ( result ) break; // stop on first unresolved child if its decision hub is sequential
322  }
323  }
324 
325  if ( oldSlot ) m_slot = oldSlot;
326  return false;
327  }
328 
329  //---------------------------------------------------------------------------
331  {
332 
333  if ( m_slot->controlFlowState[node.getNodeIndex()] != -1 ) return false;
334  return true;
335  }
336 
337  //--------------------------------------------------------------------------
339  {
340 
341  bool result = false;
342 
343  auto& states = m_slot->algsStates;
344  auto& state = states[node.getAlgoIndex()];
345 
346  // Promote with INITIAL->CR
347  if ( State::INITIAL == state ) states.updateState( node.getAlgoIndex(), State::CONTROLREADY ).ignore();
348 
349  // Try to promote with CR->DR
350  if ( State::CONTROLREADY == state ) {
351  auto promoter = DataReadyPromoter( *m_slot, m_cause, m_trace );
352  result = promoter.visit( node );
353  } else {
354  result = true;
355  }
356 
357  // return true only when an algorithm is not lower than DR in its FSM
358  // i.e., the visitor has done everything it could with this algorithm
359  return result;
360  }
361 
362  //--------------------------------------------------------------------------
364  {
365 
366  auto& products = node.getOutputDataNodes();
367  float rank = 0;
368 
369  for ( auto p : products ) rank += p->getConsumers().size();
370 
371  node.setRank( rank );
372  /*std::stringstream s;
373  s << node.getNodeName() << ", " << rank << "\n";
374  std::ofstream myfile;
375  myfile.open("AlgoRank.csv", std::ios::app);
376  myfile << s.str();
377  myfile.close();*/
378 
379  return true;
380  }
381 
382  //--------------------------------------------------------------------------
384  {
385 
386  std::ifstream myfile;
387  myfile.open( "InputExecutionPlan.graphml", std::ios::in );
388 
389  precedence::PrecTrace execPlan;
390 
392  using boost::get;
393 
394  boost::dynamic_properties dp;
395  dp.property( "name", get( &AlgoTraceProps::m_name, execPlan ) );
396  dp.property( "index", get( &AlgoTraceProps::m_index, execPlan ) );
397  dp.property( "dataRank", get( &AlgoTraceProps::m_rank, execPlan ) );
398  dp.property( "runtime", get( &AlgoTraceProps::m_runtime, execPlan ) );
399 
400  boost::read_graphml( myfile, execPlan, dp );
401 
402  typedef boost::graph_traits<precedence::PrecTrace>::vertex_iterator itV;
404 
405  for ( vp = boost::vertices( execPlan ); vp.first != vp.second; ++vp.first ) {
406  precedence::AlgoTraceVertex v = *vp.first;
407  auto index = get( &AlgoTraceProps::m_name, execPlan );
408  if ( index[v] == node.getNodeName() ) {
409  runThroughAdjacents( v, execPlan );
410  float rank = m_nodesSucceeded;
411  node.setRank( rank );
412  reset();
413  // std::cout << "Rank of " << index[v] << " is " << rank << std::endl;
414  }
415  }
416 
417  return true;
418  }
419 
420  //--------------------------------------------------------------------------
422  boost::graph_traits<precedence::PrecTrace>::vertex_descriptor vertex, precedence::PrecTrace graph )
423  {
424  typename boost::graph_traits<precedence::PrecTrace>::adjacency_iterator itVB;
425  typename boost::graph_traits<precedence::PrecTrace>::adjacency_iterator itVE;
426 
427  for ( boost::tie( itVB, itVE ) = adjacent_vertices( vertex, graph ); itVB != itVE; ++itVB ) {
428  m_nodesSucceeded += 1;
429  runThroughAdjacents( *itVB, graph );
430  }
431  }
432 
433  //--------------------------------------------------------------------------
435  {
436 
437  std::ifstream myfile;
438  myfile.open( "InputExecutionPlan.graphml", std::ios::in );
439 
440  precedence::PrecTrace execPlan;
442  using boost::get;
443 
444  boost::dynamic_properties dp;
445  dp.property( "name", get( &AlgoTraceProps::m_name, execPlan ) );
446  dp.property( "index", get( &AlgoTraceProps::m_index, execPlan ) );
447  dp.property( "dataRank", get( &AlgoTraceProps::m_rank, execPlan ) );
448  dp.property( "runtime", get( &AlgoTraceProps::m_runtime, execPlan ) );
449 
450  boost::read_graphml( myfile, execPlan, dp );
451 
452  typedef boost::graph_traits<precedence::PrecTrace>::vertex_iterator itV;
454 
455  for ( vp = boost::vertices( execPlan ); vp.first != vp.second; ++vp.first ) {
456  precedence::AlgoTraceVertex v = *vp.first;
457  auto index = get( &AlgoTraceProps::m_name, execPlan );
458  if ( index[v] == node.getNodeName() ) {
459  auto index_runtime = get( &AlgoTraceProps::m_runtime, execPlan );
460  float rank = index_runtime[v];
461  node.setRank( rank );
462  // std::cout << "Rank of " << index[v] << " is " << rank << std::endl;
463  }
464  }
465  return true;
466  }
467 
468  //--------------------------------------------------------------------------
470  {
471 
472  std::ifstream myfile;
473  myfile.open( "Eccentricity.graphml", std::ios::in );
474 
475  precedence::PrecTrace execPlan;
476 
477  boost::dynamic_properties dp;
478  using boost::get;
479 
480  dp.property( "name", get( &precedence::AlgoTraceProps::m_name, execPlan ) );
481  dp.property( "Eccentricity", get( &precedence::AlgoTraceProps::m_eccentricity, execPlan ) );
482 
483  boost::read_graphml( myfile, execPlan, dp );
484 
485  typedef boost::graph_traits<precedence::PrecTrace>::vertex_iterator itV;
487 
488  for ( vp = boost::vertices( execPlan ); vp.first != vp.second; ++vp.first ) {
489  precedence::AlgoTraceVertex v = *vp.first;
490  auto index = get( &precedence::AlgoTraceProps::m_name, execPlan );
491  if ( index[v] == node.getNodeName() ) {
492  auto index_eccentricity = get( &precedence::AlgoTraceProps::m_eccentricity, execPlan );
493  float rank = index_eccentricity[v];
494  node.setRank( rank );
495  // std::cout << "Rank of " << index[v] << " is " << rank << std::endl;
496  }
497  }
498  return true;
499  }
500 
501  //--------------------------------------------------------------------------
503  {
504 
505  // Find eccentricity of the node (only within the data realm of the execution flow graph)
506  recursiveVisit( node );
507 
508  float rank = m_maxKnownDepth;
509  node.setRank( rank );
510 
511  // Reset visitor for next nodes, if any
512  reset();
513 
514  return true;
515  }
516 
517  //--------------------------------------------------------------------------
519  {
520 
521  m_currentDepth += 1;
522 
523  auto& products = node.getOutputDataNodes();
524 
525  if ( products.empty() )
526  if ( ( m_currentDepth - 1 ) > m_maxKnownDepth ) m_maxKnownDepth = m_currentDepth - 1;
527 
528  for ( auto p : products )
529  for ( auto algoNode : p->getConsumers() ) recursiveVisit( *algoNode );
530 
531  m_currentDepth -= 1;
532  }
533 
534  //---------------------------------------------------------------------------
536  {
537 
538  if ( m_slot->controlFlowState[node.getNodeIndex()] != 1 ) return true;
539  return false;
540  }
541 
542  //---------------------------------------------------------------------------
544  {
545 
546  bool allChildDecisionsResolved = true;
547 
548  for ( const auto& child : node.getDaughters() ) {
549 
550  child->accept( *this );
551 
552  int childDecision = m_slot->controlFlowState[child->getNodeIndex()];
553  if ( childDecision == -1 ) allChildDecisionsResolved = false;
554 
555  // process children sequentially if their decision hub is sequential
556  if ( !node.m_modeConcurrent && childDecision == -1 ) return false;
557 
558  if ( childDecision == 1 && node.m_modeOR && node.m_modePromptDecision ) {
559  m_slot->controlFlowState[node.getNodeIndex()] = 1;
560 
561  // if a decision was made for this node, propagate the result upwards
562  for ( auto parent : node.m_parents ) {
563  parent->accept( *this );
564  }
565  return true;
566  }
567  }
568 
569  if ( allChildDecisionsResolved ) {
570  m_slot->controlFlowState[node.getNodeIndex()] = 1;
571 
572  // if a decision was made for this node, propagate the result upwards
573  for ( auto parent : node.m_parents ) {
574  parent->accept( *this );
575  }
576  }
577 
578  return allChildDecisionsResolved;
579  }
580 
581  //---------------------------------------------------------------------------
583  {
584 
585  if ( m_slot->controlFlowState[node.getNodeIndex()] != 1 ) return true;
586  return false;
587  }
588 
589  //--------------------------------------------------------------------------
591  {
592 
593  auto& states = m_slot->algsStates;
594  int& decision = m_slot->controlFlowState[node.getNodeIndex()];
595 
596  auto dataPromoter = DataReadyPromoter( *m_slot, m_cause );
597 
598  if ( State::INITIAL == states[node.getAlgoIndex()] ) {
599  states.updateState( node.getAlgoIndex(), State::CONTROLREADY );
600  if ( dataPromoter.visit( node ) ) {
601  states.updateState( node.getAlgoIndex(), State::SCHEDULED );
602  states.updateState( node.getAlgoIndex(), State::EVTACCEPTED );
603  decision = 1;
604  ++m_nodesSucceeded;
605  // std::cout << "Algorithm decided: " << node.getNodeName() << std::endl;
606  return true;
607  }
608  } else if ( State::CONTROLREADY == states[node.getAlgoIndex()] && dataPromoter.visit( node ) ) {
609  states.updateState( node.getAlgoIndex(), State::SCHEDULED );
610  states.updateState( node.getAlgoIndex(), State::EVTACCEPTED );
611  decision = 1;
612  ++m_nodesSucceeded;
613  // std::cout << "Algorithm decided: " << node.getNodeName() << std::endl;
614  return true;
615  }
616 
617  return false;
618  }
619 }
const unsigned int & getAlgoIndex() const
Get algorithm index.
std::vector< DecisionNode * > m_parents
Direct parent nodes.
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.
T front(T...args)
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.
T pop(T...args)
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.
T push(T...args)
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)
T size(T...args)
std::vector< EventSlot > allSubSlots
Actual sub-slot instances.
Definition: EventSlot.h:66
STL class.
bool m_modeConcurrent
Whether all daughters will be evaluated concurrently or sequentially.
Class representing the event slot.
Definition: EventSlot.h:10
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)