The Gaudi Framework  v36r9p1 (5c15b2bb)
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  // 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.name() ) )
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.name() ) {
170  oldSlot = m_slot;
172  }
173 
174  // If children are in sub-slots, loop over all
175  auto searchResult = m_slot->subSlotsByNode.find( node.name() );
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  // Check that this node may stil be evaluated
302  if ( node.m_modePromptDecision && m_slot->controlFlowState[node.getNodeIndex()] > -1 ) break;
303  }
304 
305  // Leave sub-slot
307  }
308  } else {
309  for ( auto child : node.getDaughters() ) {
310  bool result = child->accept( *this );
311  if ( !node.m_modeConcurrent )
312  if ( result ) break; // stop on first unresolved child if its decision hub is sequential
313 
314  // Check that this node may stil be evaluated
315  if ( node.m_modePromptDecision && m_slot->controlFlowState[node.getNodeIndex()] > -1 ) break;
316  }
317  }
318 
319  if ( oldSlot ) m_slot = oldSlot;
320  return false;
321  }
322 
323  //---------------------------------------------------------------------------
324  bool Supervisor::visitEnter( AlgorithmNode& node ) const {
325 
326  if ( m_slot->controlFlowState[node.getNodeIndex()] != -1 ) return false;
327  return true;
328  }
329 
330  //--------------------------------------------------------------------------
332 
333  bool result = false;
334 
335  auto& states = m_slot->algsStates;
336  auto& state = states[node.getAlgoIndex()];
337 
338  // Promote with INITIAL->CR
339  if ( AState::INITIAL == state ) states.set( node.getAlgoIndex(), AState::CONTROLREADY ).ignore();
340 
341  // Try to promote with CR->DR
342  if ( AState::CONTROLREADY == state ) {
343  auto promoter = DataReadyPromoter( *m_slot, m_cause, m_trace );
344  result = promoter.visit( node );
345  } else {
346  result = true;
347  }
348 
349  // return true only when an algorithm is not lower than DR in its FSM
350  // i.e., the visitor has done everything it could with this algorithm
351  return result;
352  }
353 
354  //---------------------------------------------------------------------------
356 
357  if ( m_slot->controlFlowState[node.getNodeIndex()] != 1 ) return true;
358  return false;
359  }
360 
361  //---------------------------------------------------------------------------
363 
364  bool allChildDecisionsResolved = true;
365 
366  for ( const auto& child : node.getDaughters() ) {
367 
368  child->accept( *this );
369 
370  int childDecision = m_slot->controlFlowState[child->getNodeIndex()];
371  if ( childDecision == -1 ) allChildDecisionsResolved = false;
372 
373  // process children sequentially if their decision hub is sequential
374  if ( !node.m_modeConcurrent && childDecision == -1 ) return false;
375 
376  if ( childDecision == 1 && node.m_modeOR && node.m_modePromptDecision ) {
377  m_slot->controlFlowState[node.getNodeIndex()] = 1;
378 
379  // if a decision was made for this node, propagate the result upwards
380  for ( auto parent : node.m_parents ) { parent->accept( *this ); }
381  return true;
382  }
383  }
384 
385  if ( allChildDecisionsResolved ) {
386  m_slot->controlFlowState[node.getNodeIndex()] = 1;
387 
388  // if a decision was made for this node, propagate the result upwards
389  for ( auto parent : node.m_parents ) { parent->accept( *this ); }
390  }
391 
392  return allChildDecisionsResolved;
393  }
394 
395  //---------------------------------------------------------------------------
397 
398  if ( m_slot->controlFlowState[node.getNodeIndex()] != 1 ) return true;
399  return false;
400  }
401 
402  //--------------------------------------------------------------------------
404 
405  auto& states = m_slot->algsStates;
406  int& decision = m_slot->controlFlowState[node.getNodeIndex()];
407 
408  auto dataPromoter = DataReadyPromoter( *m_slot, m_cause );
409 
410  if ( AState::INITIAL == states[node.getAlgoIndex()] ) {
411  states.set( node.getAlgoIndex(), AState::CONTROLREADY ).ignore( /* AUTOMATICALLY ADDED FOR gaudi/Gaudi!763 */ );
412  if ( dataPromoter.visit( node ) ) {
413  states.set( node.getAlgoIndex(), AState::SCHEDULED ).ignore( /* AUTOMATICALLY ADDED FOR gaudi/Gaudi!763 */ );
414  states.set( node.getAlgoIndex(), AState::EVTACCEPTED ).ignore( /* AUTOMATICALLY ADDED FOR gaudi/Gaudi!763 */ );
415  decision = 1;
417  // std::cout << "Algorithm decided: " << node.getNodeName() << std::endl;
418  return true;
419  }
420  } else if ( AState::CONTROLREADY == states[node.getAlgoIndex()] && dataPromoter.visit( node ) ) {
421  states.set( node.getAlgoIndex(), AState::SCHEDULED ).ignore( /* AUTOMATICALLY ADDED FOR gaudi/Gaudi!763 */ );
422  states.set( node.getAlgoIndex(), AState::EVTACCEPTED ).ignore( /* AUTOMATICALLY ADDED FOR gaudi/Gaudi!763 */ );
423  decision = 1;
425  // std::cout << "Algorithm decided: " << node.getNodeName() << std::endl;
426  return true;
427  }
428 
429  return false;
430  }
431 } // namespace concurrency
EventSlot::eventContext
std::unique_ptr< EventContext > eventContext
Cache for the eventContext.
Definition: EventSlot.h:83
concurrency::RunSimulator::m_nodesSucceeded
int m_nodesSucceeded
Definition: Promoters.h:107
concurrency::Supervisor
Definition: Promoters.h:64
concurrency::DecisionUpdater::m_slot
EventSlot * m_slot
Definition: Promoters.h:58
EventSlot::subSlotsByNode
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
concurrency::AlgorithmNode::getInputDataNodes
const std::vector< DataNode * > & getInputDataNodes() const
Get all consumer nodes.
Definition: PrecedenceRulesGraph.h:515
concurrency::DataReadyPromoter::m_slot
EventSlot * m_slot
Definition: Promoters.h:42
std::unordered_map::find
T find(T... args)
EventSlot
Class representing an event slot.
Definition: EventSlot.h:24
concurrency::DecisionNode::m_modeOR
bool m_modeOR
Whether acting as "and" (false) or "or" node (true)
Definition: PrecedenceRulesGraph.h:473
concurrency::ControlFlowNode::name
const std::string & name() const
Get node name.
Definition: PrecedenceRulesGraph.h:432
concurrency::DataReadyPromoter
Definition: Promoters.h:21
concurrency::AlgorithmNode::getOutputDataNodes
const std::vector< DataNode * > & getOutputDataNodes() const
Get all supplier nodes.
Definition: PrecedenceRulesGraph.h:513
concurrency::DecisionNode::m_modePromptDecision
bool m_modePromptDecision
Whether to evaluate the hub decision ASA its child decisions allow to do that.
Definition: PrecedenceRulesGraph.h:471
concurrency::DataReadyPromoter::m_trace
bool m_trace
Definition: Promoters.h:44
concurrency::SubSlotScout
Definition: Validators.h:84
concurrency::RunSimulator::visit
bool visit(DecisionNode &) override
Definition: Promoters.cpp:362
DataObjID.h
concurrency::DecisionUpdater::visit
bool visit(AlgorithmNode &) override
Definition: Promoters.cpp:104
concurrency::Supervisor::visitEnter
bool visitEnter(DecisionNode &) const override
Definition: Promoters.cpp:153
gaudirun.output
output
Definition: gaudirun.py:521
concurrency::AlgorithmNode::getParentDecisionHubs
const std::vector< DecisionNode * > & getParentDecisionHubs() const
Get all parent decision hubs.
Definition: PrecedenceRulesGraph.h:506
concurrency::DataNode::name
const DataObjID & name() const
Definition: PrecedenceRulesGraph.h:575
concurrency::DecisionUpdater::m_cause
Cause m_cause
Definition: Promoters.h:59
concurrency::RunSimulator::visitEnter
bool visitEnter(DecisionNode &) const override
Definition: Promoters.cpp:355
concurrency::AlgorithmNode
Definition: PrecedenceRulesGraph.h:487
EventSlot::entryPoint
std::string entryPoint
Event Views bookkeeping (TODO: optimize view bookkeeping)
Definition: EventSlot.h:94
concurrency::Supervisor::visit
bool visit(DecisionNode &) override
Definition: Promoters.cpp:160
concurrency::AlgorithmNode::isLiar
bool isLiar() const
Check if control flow logic is always inverted.
Definition: PrecedenceRulesGraph.h:535
concurrency::ConditionNode
Definition: PrecedenceRulesGraph.h:605
EventSlot::parentSlot
EventSlot * parentSlot
Pointer to parent slot (null for top level)
Definition: EventSlot.h:96
Cause::m_source
source m_source
Definition: PrecedenceRulesGraph.h:402
concurrency::Supervisor::m_slot
EventSlot * m_slot
Definition: Promoters.h:81
concurrency::Supervisor::m_cause
Cause m_cause
Definition: Promoters.h:82
concurrency::DecisionNode::m_modeConcurrent
bool m_modeConcurrent
Whether all daughters will be evaluated concurrently or sequentially.
Definition: PrecedenceRulesGraph.h:468
Validators.h
EventSlot::allSubSlots
std::vector< EventSlot > allSubSlots
Actual sub-slot instances.
Definition: EventSlot.h:100
concurrency::AlgorithmNode::isOptimist
bool isOptimist() const
Check if positive control flow decision is enforced.
Definition: PrecedenceRulesGraph.h:533
concurrency::ActiveLineageScout
Definition: Validators.h:52
concurrency::DecisionNode::getDaughters
const std::vector< ControlFlowNode * > & getDaughters() const
Get children nodes.
Definition: PrecedenceRulesGraph.h:462
concurrency::DecisionNode::m_inverted
bool m_inverted
Whether the selection result is negated or not.
Definition: PrecedenceRulesGraph.h:477
concurrency
Definition: PrecedenceRulesGraph.cpp:38
StatusCode::ignore
const StatusCode & ignore() const
Allow discarding a StatusCode without warning.
Definition: StatusCode.h:139
concurrency::DecisionNode
Definition: PrecedenceRulesGraph.h:442
concurrency::RunSimulator::m_slot
EventSlot * m_slot
Definition: Promoters.h:103
concurrency::DataReadyPromoter::visit
bool visit(AlgorithmNode &) override
Definition: Promoters.cpp:32
concurrency::DecisionNode::m_allPass
bool m_allPass
Whether always passing regardless of daughter results.
Definition: PrecedenceRulesGraph.h:475
concurrency::PrecedenceRulesGraph::getAlgorithmNode
AlgorithmNode * getAlgorithmNode(const std::string &algoName) const
Get the AlgorithmNode from by algorithm name using graph index.
Definition: PrecedenceRulesGraph.h:666
AlgsExecutionStates::set
StatusCode set(unsigned int iAlgo, State newState)
Definition: AlgsExecutionStates.cpp:23
Cause::source::Task
@ Task
compareRootHistos.state
def state
Definition: compareRootHistos.py:500
concurrency::DataReadyPromoter::m_cause
Cause m_cause
Definition: Promoters.h:43
AlgsExecutionStates::State
State
Execution states of the algorithms Must have contiguous integer values 0, 1...
Definition: AlgsExecutionStates.h:42
Promoters.h
concurrency::AlgorithmNode::getAlgoIndex
const unsigned int & getAlgoIndex() const
Get algorithm index.
Definition: PrecedenceRulesGraph.h:525
concurrency::DecisionUpdater::m_trace
bool m_trace
Definition: Promoters.h:60
concurrency::DataNode
Definition: PrecedenceRulesGraph.h:567
EventSlot::controlFlowState
std::vector< int > controlFlowState
State of the control flow.
Definition: EventSlot.h:87
std::unordered_map::end
T end(T... args)
concurrency::DecisionNode::m_parents
std::vector< DecisionNode * > m_parents
Direct parent nodes.
Definition: PrecedenceRulesGraph.h:481
concurrency::ConditionNode::m_condSvc
SmartIF< ICondSvc > m_condSvc
Definition: PrecedenceRulesGraph.h:620
concurrency::DataReadyPromoter::visitEnter
bool visitEnter(AlgorithmNode &) const override
Definition: Promoters.cpp:24
concurrency::RunSimulator::m_cause
Cause m_cause
Definition: Promoters.h:106
concurrency::Supervisor::m_trace
bool m_trace
Definition: Promoters.h:83
concurrency::ControlFlowNode::m_graph
PrecedenceRulesGraph * m_graph
Definition: PrecedenceRulesGraph.h:435
EventSlot::algsStates
AlgsExecutionStates algsStates
Vector of algorithms states.
Definition: EventSlot.h:85
concurrency::DataNode::getProducers
const std::vector< AlgorithmNode * > & getProducers() const
Get all data object producers.
Definition: PrecedenceRulesGraph.h:592
ICondSvc.h
concurrency::ControlFlowNode::getNodeIndex
const unsigned int & getNodeIndex() const
Get node index.
Definition: PrecedenceRulesGraph.h:430
Cause::m_sourceName
std::string m_sourceName
Definition: PrecedenceRulesGraph.h:403
concurrency::PrecedenceRulesGraph::addEdgeToPrecTrace
void addEdgeToPrecTrace(const AlgorithmNode *u, const AlgorithmNode *v)
set cause-effect connection between two algorithms in the precedence trace
Definition: PrecedenceRulesGraph.cpp:725