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