24#include <boost/property_map/transform_value_property_map.hpp>
26#define ON_DEBUG if ( msgLevel( MSG::DEBUG ) )
27#define ON_VERBOSE if ( msgLevel( MSG::VERBOSE ) )
32 const char* stateToString(
const int& stateId ) {
60 const unsigned int& recursionLevel )
const {
67 for (
auto daughter :
m_children ) daughter->printState( output, slot, recursionLevel + 2 );
75 bool result = visitor.
visit( *
this );
84 const unsigned int& recursionLevel )
const {
88 std::string indent( recursionLevel,
' ' );
92 <<
", in state: " << states[
m_algoIndex] << std::endl;
98 output << indent <<
"========" << std::endl;
104 bool wasProduced =
false;
105 if ( conditionNode ) {
108 wasProduced = !visitor.visitEnter( *conditionNode );
111 wasProduced = visitor.visit( *dataNode );
115 if ( !wasProduced ) {
119 output << indent <<
"missing conditions data: " << dataNode->name() << std::endl;
121 output << indent <<
"missing data: " << dataNode->name() << std::endl;
127 output << indent <<
"required by tool:";
128 for (
auto const& holderName : finder.
holderNames() ) {
129 if ( holderName != this->
name() ) output <<
" " << holderName;
134 if ( conditionNode ) {
137 std::vector<EventIDRange> validRanges;
140 for (
auto& range : validRanges ) { output << indent <<
"interval of validity: " << range << std::endl; }
141 if ( validRanges.empty() ) output << indent <<
"no interval(s) of validity" << std::endl;
144 output << indent <<
"can be produced by alg(s): ";
145 for (
auto algoNode : dataNode->getProducers() ) {
146 output <<
"( " << algoNode->name() <<
" in state: " << states[algoNode->getAlgoIndex()] <<
" ) ";
152 if ( !conditionNode ) {
153 std::vector<EventSlot>* testSubSlots = &slot.
allSubSlots;
161 if ( visitor.visit( *dataNode ) ) {
162 output << indent <<
"data is available at whole-event level" << std::endl;
167 for (
auto& pair : *subSlotMap ) {
168 if ( pair.second.size() > 0 ) {
169 bool madeLine =
false;
172 for (
int slotIndex : pair.second ) {
174 EventSlot* subSlot = &testSubSlots->at( slotIndex );
175 visitor.m_slot = subSlot;
176 if ( visitor.visit( *dataNode ) ) {
180 output << indent <<
"data is available in sub-slot(s) ";
183 output << slotIndex <<
", ";
186 if ( madeLine ) { output <<
"entered from " << pair.first << std::endl; }
192 output << indent <<
"========" << std::endl;
200 visitor.
visit( *
this );
229 if ( condSvc.isValid() ) {
230 info() <<
"CondSvc found. DF precedence rules will be augmented with 'Conditions'" <<
endmsg;
238 auto& condAlgs = condSvc->condAlgs();
239 for (
const auto algo : condAlgs ) {
243 debug() <<
"Detaching condition algorithm '" << algo->name() <<
"' from the CF realm.." <<
endmsg;
245 parent->m_children.erase( std::remove( parent->m_children.begin(), parent->m_children.end(), algoNode ),
246 parent->m_children.end() );
253 warning() <<
"Algorithm '" << algo->name() <<
"' is not registered in the graph" <<
endmsg;
267 const unsigned int& recursionLevel )
const {
273 m_headNode->printState( output, slot, recursionLevel );
278 bool firstPrint =
true;
280 auto& condAlgs = condSvc->condAlgs();
281 for (
const auto algo : condAlgs ) {
296 output << std::endl <<
"Detached algorithms:" << std::endl;
298 algoNode->
printState( output, slot, recursionLevel );
307 const std::string& algoName = algo->
name();
313 verbose() <<
" Inputs of " << algoName <<
": ";
317 verbose() <<
" Outputs of " << algoName <<
": ";
331 std::sort( sortedAlgs.begin(), sortedAlgs.end(),
332 [](
const auto* a,
const auto* b ) { return a->first < b->first; } );
333 for (
auto* algo : sortedAlgs ) {
336 for (
auto output : outputs ) {
338 if ( !sc.isSuccess() ) {
339 error() <<
"Extra producer (" << algo->first <<
") for DataObject @ " << output
340 <<
" has been detected: this is not allowed." <<
endmsg;
344 dataNode->addProducerNode( algo->second.get() );
345 algo->second->addOutputDataNode( dataNode );
355 std::sort( sortedAlgs.begin(), sortedAlgs.end(),
356 [](
const auto* a,
const auto* b ) { return a->first < b->first; } );
357 for (
auto* algo : sortedAlgs ) {
366 algo->second->addInputDataNode( dataNode );
384 auto& algoName = algo->
name();
390 algoNode = itA->second.get();
394 algoNode = r.first->second.get();
408 auto parentNode = itP->second.get();
410 parentNode->addDaughterNode( algoNode );
416 ON_VERBOSE verbose() <<
"Attached AlgorithmNode '" << algo->
name() <<
"' to parent DecisionNode '" << parentName
420 error() <<
"Parent DecisionNode '" << parentName <<
"' was not found" <<
endmsg;
432 std::unique_ptr<concurrency::DataNode> dataNode;
434 dataNode = std::make_unique<concurrency::DataNode>( *
this, dataPath );
440 if ( condSvc->isRegistered( dataPath ) ) {
441 dataNode = std::make_unique<concurrency::ConditionNode>( *
this, dataPath, condSvc );
446 dataNode = std::make_unique<concurrency::DataNode>( *
this, dataPath );
465 auto& decisionHubName = decisionHubAlgo->
name();
470 decisionHubNode = itA->second.get();
474 std::make_unique<concurrency::DecisionNode>( *
this,
m_nodeCounter, decisionHubName, modeConcurrent,
475 modePromptDecision, modeOR, allPass, isInverted ) );
476 decisionHubNode = r.first->second.get();
480 allPass, isInverted ),
492 auto parentNode = itP->second.get();
493 parentNode->addDaughterNode( decisionHubNode );
499 ON_VERBOSE verbose() <<
"Attached DecisionNode '" << decisionHubName <<
"' to parent DecisionNode '" << parentName
503 error() <<
"Parent DecisionNode '" << parentName <<
"' was not found" <<
endmsg;
519 headName, std::make_unique<concurrency::DecisionNode>( *
this,
m_nodeCounter, headName, modeConcurrent,
520 modePromptDecision, modeOR, allPass, isInverted ) );
526 allPass, isInverted ),
537 auto i = std::find_if( vp.first, vp.second, [&](
const PRVertexDesc& v ) {
538 return std::visit( precedence::VertexName(), m_PRGraph[v] ) == name;
558 info() <<
"Starting ranking by data outputs .. " <<
endmsg;
561 pair.second->accept( ranker );
562 ON_DEBUG debug() <<
" ... rank of " << pair.first <<
": " << pair.second->getRank() <<
endmsg;
567 std::ostringstream ost;
573 const int& indent )
const {
574 ost << std::string( indent * 2,
' ' );
579 ost <<
node->name() <<
" [Seq] ";
582 ost << ( ( dn->
m_modeOR ) ?
" [OR] " :
"" );
583 ost << ( ( dn->
m_allPass ) ?
" [PASS] " :
"" );
587 }
else if ( an != 0 ) {
588 ost <<
node->name() <<
" [Alg] ";
590 ost <<
" [n= " << ar->cardinality() <<
"]";
591 ost << ( ( !ar->isClonable() ) ?
" [unclonable] " :
"" );
599 const char idt[] =
" ";
600 std::ostringstream ost;
602 ost <<
"\n" << idt <<
"====================================\n";
603 ost << idt <<
"Data origins and destinations:\n";
604 ost << idt <<
"====================================\n";
606 std::vector<const DataObjID*> vec;
609 std::sort( vec.begin(), vec.end(),
610 [](
const DataObjID* a,
const DataObjID* b ) { return a->fullKey() < b->fullKey(); } );
615 for (
auto algoNode :
node.getProducers() ) ost << idt <<
" " << algoNode->name() <<
"\n";
617 ost << idt <<
" V\n";
618 ost << idt <<
" o " <<
id <<
"\n";
619 ost << idt <<
" V\n";
621 for (
auto algoNode :
node.getConsumers() ) ost << idt <<
" " << algoNode->name() <<
"\n";
623 ost << idt <<
"====================================\n";
632 std::ofstream myfile;
633 myfile.open( fileName.c_str(), std::ios::app );
636 boost::dynamic_properties dp;
638 dp.property(
"Entity",
639 boost::make_transform_value_property_map(
641 return std::visit( [](
const auto& w ) {
return boost::lexical_cast<std::string>( w ); }, v );
643 boost::get( boost::vertex_bundle,
m_PRGraph ) ) );
645 auto add_prop = [&](
auto name,
auto&& vis ) {
646 dp.property(
name, boost::make_transform_value_property_map(
648 return std::visit( vis, v );
650 boost::get( boost::vertex_bundle,
m_PRGraph ) ) );
666 boost::write_graphml( myfile,
m_PRGraph, dp );
673 std::ofstream myfile;
674 myfile.open( fileName.c_str(), std::ios::app );
678 if ( !timelineSvc.
isValid() ) {
679 warning() <<
"Failed to get the TimelineSvc, timing will not be added to "
680 <<
"the task precedence trace dump" <<
endmsg;
683 std::vector<long long int> start_times;
685 for (
auto vp = vertices(
m_precTrace ); vp.first != vp.second; ++vp.first ) {
692 timelineSvc->getFirstMatching( te );
693 auto start_point = te.
start;
694 timelineSvc->getLastMatching( te );
695 auto end_point = te.
end;
696 long int runtime{ std::chrono::duration_cast<std::chrono::microseconds>( end_point - start_point ).count() };
700 std::chrono::duration_cast<std::chrono::nanoseconds>( start_point.time_since_epoch() ).count() };
702 if ( start != 0 ) start_times.push_back( start );
705 auto min = std::min_element( start_times.begin(), start_times.end() );
707 for (
auto vp = vertices(
m_precTrace ); vp.first != vp.second; ++vp.first ) {
711 if ( oldValue != 0 ) oldValue = oldValue - *min;
716 boost::dynamic_properties dp;
719 dp.property(
"Name", get( &AlgoTraceProps::m_name,
m_precTrace ) );
720 dp.property(
"Rank", get( &AlgoTraceProps::m_rank,
m_precTrace ) );
721 dp.property(
"Run Time (us)", get( &AlgoTraceProps::m_runtime,
m_precTrace ) );
722 dp.property(
"Start Time (ns)", get( &AlgoTraceProps::m_start,
m_precTrace ) );
731 std::string u_name = u ==
nullptr ?
"ENTRY" : u->
name();
732 std::string v_name = v->
name();
739 source = itT->second;
747 source = itS->second;
760 target = itP->second;
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
MsgStream & error() const
shortcut for the method msgStream(MSG::ERROR)
MsgStream & verbose() const
shortcut for the method msgStream(MSG::VERBOSE)
MsgStream & warning() const
shortcut for the method msgStream(MSG::WARNING)
MsgStream & debug() const
shortcut for the method msgStream(MSG::DEBUG)
MsgStream & info() const
shortcut for the method msgStream(MSG::INFO)
Implements the IDataHandleVisitor interface Class used to explore heirarchy of nested IDataHandleHold...
std::vector< std::string > & holderNames()
const DataObjIDColl & outputDataObjs() const override
const DataObjIDColl & inputDataObjs() const override
const EventIDBase & eventID() const
This class provides a unique identification for each event, in terms of run/event number and/or a tim...
Base class from which all concrete algorithm classes should be derived.
void acceptDHVisitor(IDataHandleVisitor *) const override
const std::string & name() const override
The identifying name of the algorithm object.
virtual StatusCode validRanges(std::vector< EventIDRange > &ranges, const DataObjID &id) const =0
retrieve all valid ranges for one Object ID
virtual SmartIF< IService > & service(const Gaudi::Utils::TypeNameString &typeName, const bool createIf=true)=0
Returns a smart pointer to a service.
Small smart pointer class with automatic reference counting for IInterface.
bool isValid() const
Allow for check if smart pointer is valid.
This class is used for returning status codes from appropriate routines.
void ignore() const
Allow discarding a StatusCode without warning.
constexpr static const auto SUCCESS
constexpr static const auto FAILURE
void addParentNode(DecisionNode *node)
Add a parent node.
std::vector< DecisionNode * > m_parents
Control flow parents of an AlgorithmNode (DecisionNodes).
std::vector< DataNode * > m_inputs
Algorithm inputs (DataNodes).
float getRank() const
Get Algorithm rank.
const std::vector< DataNode * > & getInputDataNodes() const
Get all consumer nodes.
const std::vector< DecisionNode * > & getParentDecisionHubs() const
Get all parent decision hubs.
std::vector< DataNode * > m_outputs
Algorithm outputs (DataNodes).
Gaudi::Algorithm * getAlgorithm() const
get Algorithm representatives
void addInputDataNode(DataNode *node)
Associate an AlgorithmNode, which is a data consumer of this one.
unsigned int getAlgoIndex() const
Get algorithm index.
void addOutputDataNode(DataNode *node)
Associate an AlgorithmNode, which is a data supplier for this one.
void printState(std::stringstream &output, EventSlot &slot, const unsigned int &recursionLevel) const override
Print a string representing the control flow state.
bool accept(IGraphVisitor &visitor) override
Visitor entry point.
unsigned int m_algoIndex
The index of the algorithm.
SmartIF< ICondSvc > m_condSvc
ControlFlowNode(PrecedenceRulesGraph &graph, unsigned int nodeIndex, const std::string &name)
Constructor.
const std::string & name() const
Get node name.
void addConsumerNode(AlgorithmNode *node)
Add relationship to consumer AlgorithmNode.
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.
void addDaughterNode(ControlFlowNode *node)
Add a daughter node.
bool m_allPass
Whether always passing regardless of daughter results.
void printState(std::stringstream &output, EventSlot &slot, const unsigned int &recursionLevel) const override
Print a string representing the control flow state.
std::vector< ControlFlowNode * > m_children
All direct daughter nodes in the tree.
bool accept(IGraphVisitor &visitor) override
Visitor entry point.
bool m_modePromptDecision
Whether to evaluate the hub decision ASA its child decisions allow to do that.
DecisionNode(PrecedenceRulesGraph &graph, unsigned int nodeIndex, const std::string &name, Concurrent modeConcurrent, PromptDecision modePromptDecision, ModeOr modeOR, AllPass allPass, Inverted isInverted)
Constructor.
void addParentNode(DecisionNode *node)
Add a parent node.
std::vector< DecisionNode * > m_parents
Direct parent nodes.
virtual bool visit(DecisionNode &)
virtual bool visitEnter(DecisionNode &) const
StatusCode addAlgorithmNode(Gaudi::Algorithm *daughterAlgo, const std::string &parentName)
Add algorithm node.
void addEdgeToPrecTrace(const AlgorithmNode *u, const AlgorithmNode *v)
set cause-effect connection between two algorithms in the precedence trace
void registerIODataObjects(const Gaudi::Algorithm *algo)
Register algorithm in the Data Dependency index.
precedence::PRGraph m_PRGraph
BGL-based graph of precedence rules.
std::unordered_map< std::string, std::unique_ptr< DecisionNode > > m_decisionNameToDecisionHubMap
Index: map of decision's name to DecisionHub.
void printState(std::stringstream &output, EventSlot &slot, const unsigned int &recursionLevel) const
Print a string representing the control flow state.
StatusCode initialize()
Initialize graph.
std::map< std::string, precedence::AlgoTraceVertex > m_prec_trace_map
StatusCode addDataNode(const DataObjID &dataPath)
Add DataNode that represents DataObject.
DecisionNode * m_headNode
the head node of the control flow graph
DataNode * getDataNode(const DataObjID &dataPath) const
Get DataNode by DataObject path using graph index.
std::unordered_map< std::string, DataObjIDColl > m_algoNameToAlgoInputsMap
Indexes: maps of algorithm's name to algorithm's inputs/outputs.
precedence::PrecTrace m_precTrace
facilities for algorithm precedence tracing
SmartIF< ISvcLocator > m_svcLocator
Service locator (needed to access the MessageSvc).
StatusCode buildDataDependenciesRealm()
Build data dependency realm WITH data object nodes participating.
std::string dumpDataFlow() const
Print out all data origins and destinations, as reflected in the EF graph.
PRVertexDesc node(const std::string &) const
std::unordered_map< DataObjID, std::unique_ptr< DataNode >, DataObjID_Hasher > m_dataPathToDataNodeMap
Index: map of data path to DataNode.
void addHeadNode(const std::string &headName, concurrency::Concurrent, concurrency::PromptDecision, concurrency::ModeOr, concurrency::AllPass, concurrency::Inverted)
Add a node, which has no parents.
StatusCode addDecisionHubNode(Gaudi::Algorithm *daughterAlgo, const std::string &parentName, concurrency::Concurrent, concurrency::PromptDecision, concurrency::ModeOr, concurrency::AllPass, concurrency::Inverted)
Add a node, which aggregates decisions of direct daughter nodes.
void accept(IGraphVisitor &visitor) const
An entry point to visit all graph nodes.
std::unordered_map< std::string, std::unique_ptr< AlgorithmNode > > m_algoNameToAlgoNodeMap
Index: map of algorithm's name to AlgorithmNode.
bool m_conditionsRealmEnabled
Enable conditions realm of precedence rules.
void dumpPrecRules(const std::filesystem::path &, const EventSlot &slot)
dump to file the precedence rules
unsigned int m_algoCounter
Total number of algorithm nodes in the graph.
void rankAlgorithms(IGraphVisitor &ranker) const
Rank Algorithm nodes by the number of data outputs.
std::unordered_map< std::string, DataObjIDColl > m_algoNameToAlgoOutputsMap
unsigned int m_nodeCounter
Total number of nodes in the graph.
std::string dumpControlFlow() const
Print out control flow of Algorithms and Sequences.
void dumpPrecTrace(const std::filesystem::path &, const EventSlot &slot)
dump to file the precedence trace
const std::string & name() const override
Retrieve name of the service.
SmartIF< ISvcLocator > & serviceLocator() const override
Retrieve pointer to service locator.
Gaudi::tagged_bool< class AllPass_tag > AllPass
Gaudi::tagged_bool< class Concurrent_tag > Concurrent
Gaudi::tagged_bool< class ModeOr_tag > ModeOr
Gaudi::tagged_bool< class PromptDecision_tag > PromptDecision
Gaudi::tagged_bool< class Inverted_tag > Inverted
boost::graph_traits< PrecTrace >::vertex_descriptor AlgoTraceVertex
boost::graph_traits< PRGraph >::vertex_descriptor PRVertexDesc
std::variant< AlgoProps, DecisionHubProps, DataProps, CondDataProps > VariantVertexProps
Class representing an event slot.
std::unique_ptr< EventContext > eventContext
Cache for the eventContext.
std::vector< EventSlot > allSubSlots
Actual sub-slot instances.
EventSlot * parentSlot
Pointer to parent slot (null for top level).
std::string entryPoint
Event Views bookkeeping (TODO: optimize view bookkeeping).
std::unordered_map< std::string, std::vector< unsigned int > > subSlotsByNode
Listing of sub-slots by the node (name) they are attached to.
AlgsExecutionStates algsStates
Vector of algorithms states.
std::vector< int > controlFlowState
State of the control flow.