The Gaudi Framework  master (37c0b60a)
Promoters.cpp
Go to the documentation of this file.
1 /***********************************************************************************\
2 * (c) Copyright 1998-2024 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  const int decision = [state]() {
109  switch ( state ) {
110  case AState::EVTACCEPTED:
111  return 1;
112  case AState::EVTREJECTED:
113  return 0;
114  default:
115  return -1;
116  };
117  }();
118 
119  if ( -1 == decision ) { return false; }
120 
121  m_slot->controlFlowState[node.getNodeIndex()] = decision;
122 
123  auto promoter = DataReadyPromoter( *m_slot, m_cause, m_trace );
124  for ( const auto& output : node.getOutputDataNodes() )
125  for ( auto& consumer : output->getConsumers() ) consumer->accept( promoter );
126 
127  // propagate decision upward to active regions of the graph
129  auto& parents = node.getParentDecisionHubs();
130  if ( parents.size() == 1 ) {
131  parents[0]->accept( vis );
132  } else if ( m_slot->parentSlot ) {
133  auto scout = SubSlotScout( m_slot, node );
134  for ( auto& p : parents ) {
135  p->accept( scout );
136  if ( scout.reply() ) p->accept( vis );
137  scout.reset();
138  }
139  } else {
140  auto scout = ActiveLineageScout( m_slot, node );
141  for ( auto& p : parents ) {
142  p->accept( scout );
143  if ( scout.reply() ) p->accept( vis );
144  scout.reset();
145  }
146  }
147 
148  return true; // return true only if the algorithm produced a decision
149  }
150 
151  //---------------------------------------------------------------------------
152  bool Supervisor::visitEnter( DecisionNode& node ) const {
153 
154  if ( m_slot->controlFlowState[node.getNodeIndex()] != -1 ) return false;
155  return true;
156  }
157 
158  //---------------------------------------------------------------------------
160 
161  bool foundNonResolvedChild = false;
162  bool foundNegativeChild = false;
163  bool foundPositiveChild = false;
164  int decision = -1;
165 
166  // Leave a sub-slot if this is the exit node
167  EventSlot* oldSlot = nullptr;
168  if ( m_slot->parentSlot && m_slot->entryPoint == node.name() ) {
169  oldSlot = m_slot;
171  }
172 
173  // If children are in sub-slots, loop over all
174  auto searchResult = m_slot->subSlotsByNode.find( node.name() );
175  if ( searchResult != m_slot->subSlotsByNode.end() ) {
176  bool breakout = false;
177  for ( unsigned int slotIndex : searchResult->second ) {
178 
179  // Enter the sub-slot
180  m_slot = &( m_slot->allSubSlots[slotIndex] );
181 
182  for ( auto child : node.getDaughters() ) {
183 
184  int& childDecision = m_slot->controlFlowState[child->getNodeIndex()];
185 
186  if ( childDecision == -1 )
187  foundNonResolvedChild = true;
188  else if ( childDecision == 1 )
189  foundPositiveChild = true;
190  else
191  foundNegativeChild = true;
192 
193  if ( node.m_modePromptDecision ) {
194  if ( node.m_modeOR && foundPositiveChild ) {
195  decision = 1;
196  breakout = true;
197  break;
198  } else if ( !node.m_modeOR && foundNegativeChild ) {
199  decision = 0;
200  breakout = true;
201  break;
202  }
203  } else {
204  if ( foundNonResolvedChild ) {
205  breakout = true;
206  break;
207  }
208  }
209  }
210 
211  // Leave the sub-slot
213  if ( breakout ) break;
214  }
215  } else {
216  for ( auto child : node.getDaughters() ) {
217  int& childDecision = m_slot->controlFlowState[child->getNodeIndex()];
218 
219  if ( childDecision == -1 )
220  foundNonResolvedChild = true;
221  else if ( childDecision == 1 )
222  foundPositiveChild = true;
223  else
224  foundNegativeChild = true;
225 
226  if ( node.m_modePromptDecision ) {
227  if ( node.m_modeOR && foundPositiveChild ) {
228  decision = 1;
229  break;
230  } else if ( !node.m_modeOR && foundNegativeChild ) {
231  decision = 0;
232  break;
233  }
234  } else {
235  if ( foundNonResolvedChild ) break;
236  }
237  }
238  } // end monitoring children
239 
240  if ( !foundNonResolvedChild && decision == -1 ) {
241  if ( node.m_modeOR ) { // OR
242  if ( foundPositiveChild )
243  decision = 1;
244  else
245  decision = 0;
246  } else { // AND
247  if ( foundNegativeChild )
248  decision = 0;
249  else
250  decision = 1;
251  }
252  }
253 
254  if ( node.m_inverted && decision == 1 )
255  decision = 0;
256  else if ( node.m_inverted && decision == 0 )
257  decision = 1;
258 
259  if ( node.m_allPass && !foundNonResolvedChild ) decision = 1;
260 
261  if ( decision != -1 ) {
262  m_slot->controlFlowState[node.getNodeIndex()] = decision;
263 
264  // propagate aggregated decision upward to active regions of the graph
265  if ( node.m_parents.size() == 1 ) {
266  node.m_parents[0]->accept( *this );
267  } else if ( m_slot->parentSlot ) {
268  auto scout = SubSlotScout( m_slot, node );
269  for ( auto& p : node.m_parents ) {
270  p->accept( scout );
271  if ( scout.reply() ) p->accept( *this );
272  scout.reset();
273  }
274  } else {
275  auto scout = ActiveLineageScout( m_slot, node );
276  for ( auto& p : node.m_parents ) {
277  p->accept( scout );
278  if ( scout.reply() ) p->accept( *this );
279  scout.reset();
280  }
281  }
282 
283  if ( oldSlot ) m_slot = oldSlot;
284  return true;
285  }
286 
287  // if no decision can be made yet, request further information downwards
288  // Enter subslots for children if needed
289  if ( searchResult != m_slot->subSlotsByNode.end() ) {
290  for ( unsigned int slotIndex : searchResult->second ) {
291 
292  // Enter sub-slot
293  m_slot = &( m_slot->allSubSlots[slotIndex] );
294 
295  for ( auto child : node.getDaughters() ) {
296  bool result = child->accept( *this );
297  if ( !node.m_modeConcurrent )
298  if ( result ) break; // stop on first unresolved child if its decision hub is sequential
299 
300  // Check that this node may stil be evaluated
301  if ( node.m_modePromptDecision && m_slot->controlFlowState[node.getNodeIndex()] > -1 ) break;
302  }
303 
304  // Leave sub-slot
306  }
307  } else {
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  // Check that this node may stil be evaluated
314  if ( node.m_modePromptDecision && m_slot->controlFlowState[node.getNodeIndex()] > -1 ) break;
315  }
316  }
317 
318  if ( oldSlot ) m_slot = oldSlot;
319  return false;
320  }
321 
322  //---------------------------------------------------------------------------
323  bool Supervisor::visitEnter( AlgorithmNode& node ) const {
324 
325  if ( m_slot->controlFlowState[node.getNodeIndex()] != -1 ) return false;
326  return true;
327  }
328 
329  //--------------------------------------------------------------------------
331 
332  bool result = false;
333 
334  auto& states = m_slot->algsStates;
335  auto& state = states[node.getAlgoIndex()];
336 
337  // Promote with INITIAL->CR
338  if ( AState::INITIAL == state ) states.set( node.getAlgoIndex(), AState::CONTROLREADY ).ignore();
339 
340  // Try to promote with CR->DR
341  if ( AState::CONTROLREADY == state ) {
342  auto promoter = DataReadyPromoter( *m_slot, m_cause, m_trace );
343  result = promoter.visit( node );
344  } else {
345  result = true;
346  }
347 
348  // return true only when an algorithm is not lower than DR in its FSM
349  // i.e., the visitor has done everything it could with this algorithm
350  return result;
351  }
352 
353  //---------------------------------------------------------------------------
355 
356  if ( m_slot->controlFlowState[node.getNodeIndex()] != 1 ) return true;
357  return false;
358  }
359 
360  //---------------------------------------------------------------------------
362 
363  bool allChildDecisionsResolved = true;
364 
365  for ( const auto& child : node.getDaughters() ) {
366 
367  child->accept( *this );
368 
369  int childDecision = m_slot->controlFlowState[child->getNodeIndex()];
370  if ( childDecision == -1 ) allChildDecisionsResolved = false;
371 
372  // process children sequentially if their decision hub is sequential
373  if ( !node.m_modeConcurrent && childDecision == -1 ) return false;
374 
375  if ( childDecision == 1 && node.m_modeOR && node.m_modePromptDecision ) {
376  m_slot->controlFlowState[node.getNodeIndex()] = 1;
377 
378  // if a decision was made for this node, propagate the result upwards
379  for ( auto parent : node.m_parents ) { parent->accept( *this ); }
380  return true;
381  }
382  }
383 
384  if ( allChildDecisionsResolved ) {
385  m_slot->controlFlowState[node.getNodeIndex()] = 1;
386 
387  // if a decision was made for this node, propagate the result upwards
388  for ( auto parent : node.m_parents ) { parent->accept( *this ); }
389  }
390 
391  return allChildDecisionsResolved;
392  }
393 
394  //---------------------------------------------------------------------------
396 
397  if ( m_slot->controlFlowState[node.getNodeIndex()] != 1 ) return true;
398  return false;
399  }
400 
401  //--------------------------------------------------------------------------
403 
404  auto& states = m_slot->algsStates;
405  int& decision = m_slot->controlFlowState[node.getNodeIndex()];
406 
407  auto dataPromoter = DataReadyPromoter( *m_slot, m_cause );
408 
409  if ( AState::INITIAL == states[node.getAlgoIndex()] ) {
410  states.set( node.getAlgoIndex(), AState::CONTROLREADY ).ignore( /* AUTOMATICALLY ADDED FOR gaudi/Gaudi!763 */ );
411  if ( dataPromoter.visit( node ) ) {
412  states.set( node.getAlgoIndex(), AState::SCHEDULED ).ignore( /* AUTOMATICALLY ADDED FOR gaudi/Gaudi!763 */ );
413  states.set( node.getAlgoIndex(), AState::EVTACCEPTED ).ignore( /* AUTOMATICALLY ADDED FOR gaudi/Gaudi!763 */ );
414  decision = 1;
416  // std::cout << "Algorithm decided: " << node.getNodeName() << std::endl;
417  return true;
418  }
419  } else if ( AState::CONTROLREADY == states[node.getAlgoIndex()] && dataPromoter.visit( node ) ) {
420  states.set( node.getAlgoIndex(), AState::SCHEDULED ).ignore( /* AUTOMATICALLY ADDED FOR gaudi/Gaudi!763 */ );
421  states.set( node.getAlgoIndex(), AState::EVTACCEPTED ).ignore( /* AUTOMATICALLY ADDED FOR gaudi/Gaudi!763 */ );
422  decision = 1;
424  // std::cout << "Algorithm decided: " << node.getNodeName() << std::endl;
425  return true;
426  }
427 
428  return false;
429  }
430 } // 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:510
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:470
concurrency::ControlFlowNode::name
const std::string & name() const
Get node name.
Definition: PrecedenceRulesGraph.h:429
concurrency::DataReadyPromoter
Definition: Promoters.h:21
concurrency::AlgorithmNode::getOutputDataNodes
const std::vector< DataNode * > & getOutputDataNodes() const
Get all supplier nodes.
Definition: PrecedenceRulesGraph.h:508
concurrency::DecisionNode::m_modePromptDecision
bool m_modePromptDecision
Whether to evaluate the hub decision ASA its child decisions allow to do that.
Definition: PrecedenceRulesGraph.h:468
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:361
DataObjID.h
concurrency::DecisionUpdater::visit
bool visit(AlgorithmNode &) override
Definition: Promoters.cpp:104
concurrency::Supervisor::visitEnter
bool visitEnter(DecisionNode &) const override
Definition: Promoters.cpp:152
gaudirun.output
output
Definition: gaudirun.py:521
concurrency::AlgorithmNode::getParentDecisionHubs
const std::vector< DecisionNode * > & getParentDecisionHubs() const
Get all parent decision hubs.
Definition: PrecedenceRulesGraph.h:501
concurrency::DataNode::name
const DataObjID & name() const
Definition: PrecedenceRulesGraph.h:561
concurrency::DecisionUpdater::m_cause
Cause m_cause
Definition: Promoters.h:59
concurrency::RunSimulator::visitEnter
bool visitEnter(DecisionNode &) const override
Definition: Promoters.cpp:354
concurrency::AlgorithmNode::getAlgoIndex
unsigned int getAlgoIndex() const
Get algorithm index.
Definition: PrecedenceRulesGraph.h:520
concurrency::AlgorithmNode
Definition: PrecedenceRulesGraph.h:484
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:159
concurrency::ConditionNode
Definition: PrecedenceRulesGraph.h:591
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:399
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:465
Validators.h
EventSlot::allSubSlots
std::vector< EventSlot > allSubSlots
Actual sub-slot instances.
Definition: EventSlot.h:100
concurrency::ActiveLineageScout
Definition: Validators.h:52
concurrency::DecisionNode::getDaughters
const std::vector< ControlFlowNode * > & getDaughters() const
Get children nodes.
Definition: PrecedenceRulesGraph.h:459
concurrency::DecisionNode::m_inverted
bool m_inverted
Whether the selection result is negated or not.
Definition: PrecedenceRulesGraph.h:474
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:439
concurrency::RunSimulator::m_slot
EventSlot * m_slot
Definition: Promoters.h:105
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:472
concurrency::PrecedenceRulesGraph::getAlgorithmNode
AlgorithmNode * getAlgorithmNode(const std::string &algoName) const
Get the AlgorithmNode from by algorithm name using graph index.
Definition: PrecedenceRulesGraph.h:651
AlgsExecutionStates::set
StatusCode set(unsigned int iAlgo, State newState)
Definition: AlgsExecutionStates.cpp:23
Cause::source::Task
@ Task
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::DecisionUpdater::m_trace
bool m_trace
Definition: Promoters.h:60
concurrency::DataNode
Definition: PrecedenceRulesGraph.h:553
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:478
concurrency::ConditionNode::m_condSvc
SmartIF< ICondSvc > m_condSvc
Definition: PrecedenceRulesGraph.h:606
concurrency::DataReadyPromoter::visitEnter
bool visitEnter(AlgorithmNode &) const override
Definition: Promoters.cpp:24
compareRootHistos.state
state
Definition: compareRootHistos.py:496
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:432
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:578
ICondSvc.h
concurrency::ControlFlowNode::getNodeIndex
const unsigned int & getNodeIndex() const
Get node index.
Definition: PrecedenceRulesGraph.h:427
Cause::m_sourceName
std::string m_sourceName
Definition: PrecedenceRulesGraph.h:400
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:719