The Gaudi Framework  v32r2 (46d42edc)
Promoters.cpp
Go to the documentation of this file.
1 #include "Promoters.h"
2 #include "../../AlgsExecutionStates.h"
3 #include "Validators.h"
4 
6 #include "GaudiKernel/ICondSvc.h"
7 
8 #include <queue>
9 
10 namespace concurrency {
12 
13  //--------------------------------------------------------------------------
15 
16  if ( AState::CONTROLREADY != m_slot->algsStates[node.getAlgoIndex()] ) return false;
17 
18  return true;
19  }
20 
21  //--------------------------------------------------------------------------
23 
24  bool result = true; // return true if this algorithm has no data inputs
25 
26  for ( auto dataNode : node.getInputDataNodes() ) {
27 
28  result = dataNode->accept( *this );
29 
30  // With ConditionNodes, one may decide NOT to break here so that associated
31  // ConditionAlgorithms are scheduled ASAP. This behavior can be made configurable
32  if ( !result ) break; // skip checking other inputs if this input was not produced yet
33  }
34 
35  if ( result ) {
36  m_slot->algsStates.set( node.getAlgoIndex(), AState::DATAREADY ).ignore();
37 
38  if ( m_trace ) {
39  auto sourceNode = ( m_cause.m_source == Cause::source::Task )
41  : nullptr;
42  node.m_graph->addEdgeToPrecTrace( sourceNode, &node );
43  }
44  }
45 
46  // return true only if an algorithm is promoted to DR
47  return result;
48  }
49 
50  //--------------------------------------------------------------------------
51  bool DataReadyPromoter::visitEnter( DataNode& ) const { return true; }
52 
53  //--------------------------------------------------------------------------
55  /* Implements 'observer' strategy, i.e., only check if producer of this DataNode
56  * has been already executed or not */
57 
58  auto const& producers = node.getProducers();
59  for ( auto algoNode : producers ) {
60  const auto& state = m_slot->algsStates[algoNode->getAlgoIndex()];
61  if ( AState::EVTACCEPTED == state || AState::EVTREJECTED == state ) {
62  return true; // skip checking other producers if one was found to be executed
63  }
64  }
65 
66  // Check parent slot if necessary
67  if ( m_slot->parentSlot ) {
68  for ( auto algoNode : producers ) {
69  const auto& state = m_slot->parentSlot->algsStates[algoNode->getAlgoIndex()];
70  if ( AState::EVTACCEPTED == state || AState::EVTREJECTED == state ) {
71  return true; // skip checking other producers if one was found to be executed
72  }
73  }
74  }
75 
76  // return true only if this DataNode is produced
77  return false;
78  }
79 
80  //--------------------------------------------------------------------------
82 
83  if ( node.m_condSvc->isValidID( *( m_slot->eventContext ), node.getPath() ) )
84  return false; // do not enter this ConditionNode if the condition has bee already loaded
85 
86  return true;
87  }
88 
89  //--------------------------------------------------------------------------
91  /* Implements 'requester' strategy, i.e., requests this ConditionNode to be loaded
92  * by its associated ConditionAlgorithm */
93 
94  auto promoter = Supervisor( *m_slot, m_cause, m_trace );
95 
96  for ( auto condAlg : node.getProducers() ) condAlg->accept( promoter );
97 
98  // this method is called if, and only if, this ConditionNode is not yet produced.
99  // thus, by definition, this ConditionNode is not yet available at this moment
100  return false;
101  }
102 
103  //--------------------------------------------------------------------------
105 
106  auto& states = m_slot->algsStates;
107  const AState& state = states[node.getAlgoIndex()];
108  int decision = -1;
109 
110  if ( true == node.isOptimist() )
111  decision = 1;
112  else if ( AState::EVTACCEPTED == state )
113  decision = !node.isLiar();
114  else if ( AState::EVTREJECTED == state )
115  decision = node.isLiar();
116 
117  if ( -1 != decision ) {
118 
119  m_slot->controlFlowState[node.getNodeIndex()] = decision;
120 
121  auto promoter = DataReadyPromoter( *m_slot, m_cause, m_trace );
122  for ( const auto& output : node.getOutputDataNodes() )
123  for ( auto& consumer : output->getConsumers() ) consumer->accept( promoter );
124 
125  // propagate decision upward to active regions of the graph
127  auto& parents = node.getParentDecisionHubs();
128  if ( parents.size() == 1 ) {
129  parents[0]->accept( vis );
130  } else if ( m_slot->parentSlot ) {
131  auto scout = SubSlotScout( m_slot, node );
132  for ( auto& p : parents ) {
133  p->accept( scout );
134  if ( scout.reply() ) p->accept( vis );
135  scout.reset();
136  }
137  } else {
138  auto scout = ActiveLineageScout( m_slot, node );
139  for ( auto& p : parents ) {
140  p->accept( scout );
141  if ( scout.reply() ) p->accept( vis );
142  scout.reset();
143  }
144  }
145 
146  return true; // return true only if the algorithm produced a decision
147  }
148 
149  return false;
150  }
151 
152  //---------------------------------------------------------------------------
153  bool Supervisor::visitEnter( DecisionNode& node ) const {
154 
155  if ( m_slot->controlFlowState[node.getNodeIndex()] != -1 ) return false;
156  return true;
157  }
158 
159  //---------------------------------------------------------------------------
161 
162  bool foundNonResolvedChild = false;
163  bool foundNegativeChild = false;
164  bool foundPositiveChild = false;
165  int decision = -1;
166 
167  // Leave a sub-slot if this is the exit node
168  EventSlot* oldSlot = nullptr;
169  if ( m_slot->parentSlot && m_slot->entryPoint == node.getNodeName() ) {
170  oldSlot = m_slot;
172  }
173 
174  // If children are in sub-slots, loop over all
175  auto searchResult = m_slot->subSlotsByNode.find( node.getNodeName() );
176  if ( searchResult != m_slot->subSlotsByNode.end() ) {
177  bool breakout = false;
178  for ( unsigned int slotIndex : searchResult->second ) {
179 
180  // Enter the sub-slot
181  m_slot = &( m_slot->allSubSlots[slotIndex] );
182 
183  for ( auto child : node.getDaughters() ) {
184 
185  int& childDecision = m_slot->controlFlowState[child->getNodeIndex()];
186 
187  if ( childDecision == -1 )
188  foundNonResolvedChild = true;
189  else if ( childDecision == 1 )
190  foundPositiveChild = true;
191  else
192  foundNegativeChild = true;
193 
194  if ( node.m_modePromptDecision ) {
195  if ( node.m_modeOR && foundPositiveChild ) {
196  decision = 1;
197  breakout = true;
198  break;
199  } else if ( !node.m_modeOR && foundNegativeChild ) {
200  decision = 0;
201  breakout = true;
202  break;
203  }
204  } else {
205  if ( foundNonResolvedChild ) {
206  breakout = true;
207  break;
208  }
209  }
210  }
211 
212  // Leave the sub-slot
214  if ( breakout ) break;
215  }
216  } else {
217  for ( auto child : node.getDaughters() ) {
218  int& childDecision = m_slot->controlFlowState[child->getNodeIndex()];
219 
220  if ( childDecision == -1 )
221  foundNonResolvedChild = true;
222  else if ( childDecision == 1 )
223  foundPositiveChild = true;
224  else
225  foundNegativeChild = true;
226 
227  if ( node.m_modePromptDecision ) {
228  if ( node.m_modeOR && foundPositiveChild ) {
229  decision = 1;
230  break;
231  } else if ( !node.m_modeOR && foundNegativeChild ) {
232  decision = 0;
233  break;
234  }
235  } else {
236  if ( foundNonResolvedChild ) break;
237  }
238  }
239  } // end monitoring children
240 
241  if ( !foundNonResolvedChild && decision == -1 ) {
242  if ( node.m_modeOR ) { // OR
243  if ( foundPositiveChild )
244  decision = 1;
245  else
246  decision = 0;
247  } else { // AND
248  if ( foundNegativeChild )
249  decision = 0;
250  else
251  decision = 1;
252  }
253  }
254 
255  if ( node.m_inverted && decision == 1 )
256  decision = 0;
257  else if ( node.m_inverted && decision == 0 )
258  decision = 1;
259 
260  if ( node.m_allPass && !foundNonResolvedChild ) decision = 1;
261 
262  if ( decision != -1 ) {
263  m_slot->controlFlowState[node.getNodeIndex()] = decision;
264 
265  // propagate aggregated decision upward to active regions of the graph
266  if ( node.m_parents.size() == 1 ) {
267  node.m_parents[0]->accept( *this );
268  } else if ( m_slot->parentSlot ) {
269  auto scout = SubSlotScout( m_slot, node );
270  for ( auto& p : node.m_parents ) {
271  p->accept( scout );
272  if ( scout.reply() ) p->accept( *this );
273  scout.reset();
274  }
275  } else {
276  auto scout = ActiveLineageScout( m_slot, node );
277  for ( auto& p : node.m_parents ) {
278  p->accept( scout );
279  if ( scout.reply() ) p->accept( *this );
280  scout.reset();
281  }
282  }
283 
284  if ( oldSlot ) m_slot = oldSlot;
285  return true;
286  }
287 
288  // if no decision can be made yet, request further information downwards
289  // Enter subslots for children if needed
290  if ( searchResult != m_slot->subSlotsByNode.end() ) {
291  for ( unsigned int slotIndex : searchResult->second ) {
292 
293  // Enter sub-slot
294  m_slot = &( m_slot->allSubSlots[slotIndex] );
295 
296  for ( auto child : node.getDaughters() ) {
297  bool result = child->accept( *this );
298  if ( !node.m_modeConcurrent )
299  if ( result ) break; // stop on first unresolved child if its decision hub is sequential
300  }
301 
302  // Leave sub-slot
304  }
305  } else {
306  for ( auto child : node.getDaughters() ) {
307  bool result = child->accept( *this );
308  if ( !node.m_modeConcurrent )
309  if ( result ) break; // stop on first unresolved child if its decision hub is sequential
310  }
311  }
312 
313  if ( oldSlot ) m_slot = oldSlot;
314  return false;
315  }
316 
317  //---------------------------------------------------------------------------
318  bool Supervisor::visitEnter( AlgorithmNode& node ) const {
319 
320  if ( m_slot->controlFlowState[node.getNodeIndex()] != -1 ) return false;
321  return true;
322  }
323 
324  //--------------------------------------------------------------------------
326 
327  bool result = false;
328 
329  auto& states = m_slot->algsStates;
330  auto& state = states[node.getAlgoIndex()];
331 
332  // Promote with INITIAL->CR
333  if ( AState::INITIAL == state ) states.set( node.getAlgoIndex(), AState::CONTROLREADY ).ignore();
334 
335  // Try to promote with CR->DR
336  if ( AState::CONTROLREADY == state ) {
337  auto promoter = DataReadyPromoter( *m_slot, m_cause, m_trace );
338  result = promoter.visit( node );
339  } else {
340  result = true;
341  }
342 
343  // return true only when an algorithm is not lower than DR in its FSM
344  // i.e., the visitor has done everything it could with this algorithm
345  return result;
346  }
347 
348  //---------------------------------------------------------------------------
350 
351  if ( m_slot->controlFlowState[node.getNodeIndex()] != 1 ) return true;
352  return false;
353  }
354 
355  //---------------------------------------------------------------------------
357 
358  bool allChildDecisionsResolved = true;
359 
360  for ( const auto& child : node.getDaughters() ) {
361 
362  child->accept( *this );
363 
364  int childDecision = m_slot->controlFlowState[child->getNodeIndex()];
365  if ( childDecision == -1 ) allChildDecisionsResolved = false;
366 
367  // process children sequentially if their decision hub is sequential
368  if ( !node.m_modeConcurrent && childDecision == -1 ) return false;
369 
370  if ( childDecision == 1 && node.m_modeOR && node.m_modePromptDecision ) {
371  m_slot->controlFlowState[node.getNodeIndex()] = 1;
372 
373  // if a decision was made for this node, propagate the result upwards
374  for ( auto parent : node.m_parents ) { parent->accept( *this ); }
375  return true;
376  }
377  }
378 
379  if ( allChildDecisionsResolved ) {
380  m_slot->controlFlowState[node.getNodeIndex()] = 1;
381 
382  // if a decision was made for this node, propagate the result upwards
383  for ( auto parent : node.m_parents ) { parent->accept( *this ); }
384  }
385 
386  return allChildDecisionsResolved;
387  }
388 
389  //---------------------------------------------------------------------------
391 
392  if ( m_slot->controlFlowState[node.getNodeIndex()] != 1 ) return true;
393  return false;
394  }
395 
396  //--------------------------------------------------------------------------
398 
399  auto& states = m_slot->algsStates;
400  int& decision = m_slot->controlFlowState[node.getNodeIndex()];
401 
402  auto dataPromoter = DataReadyPromoter( *m_slot, m_cause );
403 
404  if ( AState::INITIAL == states[node.getAlgoIndex()] ) {
405  states.set( node.getAlgoIndex(), AState::CONTROLREADY );
406  if ( dataPromoter.visit( node ) ) {
407  states.set( node.getAlgoIndex(), AState::SCHEDULED );
408  states.set( node.getAlgoIndex(), AState::EVTACCEPTED );
409  decision = 1;
411  // std::cout << "Algorithm decided: " << node.getNodeName() << std::endl;
412  return true;
413  }
414  } else if ( AState::CONTROLREADY == states[node.getAlgoIndex()] && dataPromoter.visit( node ) ) {
415  states.set( node.getAlgoIndex(), AState::SCHEDULED );
416  states.set( node.getAlgoIndex(), AState::EVTACCEPTED );
417  decision = 1;
419  // std::cout << "Algorithm decided: " << node.getNodeName() << std::endl;
420  return true;
421  }
422 
423  return false;
424  }
425 } // namespace concurrency
EventSlot * m_slot
Definition: Promoters.h:71
std::string entryPoint
Event Views bookkeeping (TODO: optimize view bookkeeping)
Definition: EventSlot.h:84
Class representing an event slot.
Definition: EventSlot.h:14
std::vector< DecisionNode * > m_parents
Direct parent nodes.
const std::string & getNodeName() const
Get node name.
AlgorithmNode * getAlgorithmNode(const std::string &algoName) const
Get the AlgorithmNode from by algorithm name using graph index.
bool visit(AlgorithmNode &) override
Definition: Promoters.cpp:22
const std::vector< DecisionNode * > & getParentDecisionHubs() const
Get all parent decision hubs.
std::vector< int > controlFlowState
State of the control flow.
Definition: EventSlot.h:77
T end(T... args)
std::vector< EventSlot > allSubSlots
Actual sub-slot instances.
Definition: EventSlot.h:90
bool m_allPass
Whether always passing regardless of daughter results.
bool visit(DecisionNode &) override
Definition: Promoters.cpp:356
bool isOptimist() const
Check if positive control flow decision is enforced.
bool visitEnter(AlgorithmNode &) const override
Definition: Promoters.cpp:14
bool visit(AlgorithmNode &) override
Definition: Promoters.cpp:104
const unsigned int & getAlgoIndex() const
Get algorithm index.
bool m_modeOR
Whether acting as "and" (false) or "or" node (true)
const std::vector< AlgorithmNode * > & getProducers() const
Get all data object producers.
PrecedenceRulesGraph * m_graph
const DataObjID & getPath()
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
StatusCode set(unsigned int iAlgo, State newState)
State
Execution states of the algorithms.
const std::vector< ControlFlowNode * > & getDaughters() const
Get children nodes.
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 visitEnter(DecisionNode &) const override
Definition: Promoters.cpp:153
bool visit(DecisionNode &) override
Definition: Promoters.cpp:160
T find(T... args)
bool m_modeConcurrent
Whether all daughters will be evaluated concurrently or sequentially.
const std::vector< DataNode * > & getInputDataNodes() const
Get all consumer nodes.
bool visitEnter(DecisionNode &) const override
Definition: Promoters.cpp:349
const std::vector< DataNode * > & getOutputDataNodes() const
Get all supplier nodes.
EventSlot * parentSlot
Pointer to parent slot (null for top level)
Definition: EventSlot.h:86
bool m_inverted
Whether the selection result is negated or not.
bool isLiar() const
Check if control flow logic is always inverted.
const unsigned int & getNodeIndex() const
Get node index.
std::unordered_map< std::string, std::vector< unsigned int > > subSlotsByNode
Listing of sub-slots by the node (name) they are attached to.
Definition: EventSlot.h:88
std::unique_ptr< EventContext > eventContext
Cache for the eventContext.
Definition: EventSlot.h:73
std::string m_sourceName
AlgsExecutionStates algsStates
Vector of algorithms states.
Definition: EventSlot.h:75