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