The Gaudi Framework  master (fb0007c6)
Loading...
Searching...
No Matches
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"
13#include "Validators.h"
14
17
18#include <queue>
19
20namespace 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 )
50 ? node.m_graph->getAlgorithmNode( m_cause.m_sourceName )
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 //---------------------------------------------------------------------------
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;
170 m_slot = m_slot->parentSlot;
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
212 m_slot = m_slot->parentSlot;
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
305 m_slot = m_slot->parentSlot;
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 //---------------------------------------------------------------------------
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
State
Execution states of the algorithms Must have contiguous integer values 0, 1... N.
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
const std::vector< DataNode * > & getInputDataNodes() const
Get all consumer nodes.
const std::vector< DecisionNode * > & getParentDecisionHubs() const
Get all parent decision hubs.
unsigned int getAlgoIndex() const
Get algorithm index.
const std::vector< DataNode * > & getOutputDataNodes() const
Get all supplier nodes.
const unsigned int & getNodeIndex() const
Get node index.
const std::string & name() const
Get node name.
const DataObjID & name() const
const std::vector< AlgorithmNode * > & getProducers() const
Get all data object producers.
bool visitEnter(AlgorithmNode &) const override
Definition Promoters.cpp:24
bool visit(AlgorithmNode &) override
Definition Promoters.cpp:32
const std::vector< ControlFlowNode * > & getDaughters() const
Get children nodes.
bool m_modeOR
Whether acting as "and" (false) or "or" node (true)
bool m_modeConcurrent
Whether all daughters will be evaluated concurrently or sequentially.
bool m_inverted
Whether the selection result is negated or not.
bool m_allPass
Whether always passing regardless of daughter results.
bool m_modePromptDecision
Whether to evaluate the hub decision ASA its child decisions allow to do that.
std::vector< DecisionNode * > m_parents
Direct parent nodes.
bool visit(AlgorithmNode &) override
void addEdgeToPrecTrace(const AlgorithmNode *u, const AlgorithmNode *v)
set cause-effect connection between two algorithms in the precedence trace
AlgorithmNode * getAlgorithmNode(const std::string &algoName) const
Get the AlgorithmNode from by algorithm name using graph index.
bool visit(DecisionNode &) override
bool visitEnter(DecisionNode &) const override
bool visitEnter(DecisionNode &) const override
bool visit(DecisionNode &) override
AlgsExecutionStates::State AState
Definition Promoters.cpp:21
Class representing an event slot.
Definition EventSlot.h:23