17#include <boost/property_map/transform_value_property_map.hpp>
20#define ON_DEBUG if ( msgLevel( MSG::DEBUG ) )
21#define ON_VERBOSE if ( msgLevel( MSG::VERBOSE ) )
26 const char* stateToString(
const int& stateId ) {
54 const unsigned int& recursionLevel )
const {
61 for (
auto daughter :
m_children ) daughter->printState( output, slot, recursionLevel + 2 );
69 bool result = visitor.
visit( *
this );
78 const unsigned int& recursionLevel )
const {
82 std::string indent( recursionLevel,
' ' );
86 <<
", in state: " << states[
m_algoIndex] << std::endl;
92 output << indent <<
"========" << std::endl;
98 bool wasProduced =
false;
99 if ( conditionNode ) {
102 wasProduced = !visitor.visitEnter( *conditionNode );
105 wasProduced = visitor.visit( *dataNode );
109 if ( !wasProduced ) {
113 output << indent <<
"missing conditions data: " << dataNode->name() << std::endl;
115 output << indent <<
"missing data: " << dataNode->name() << std::endl;
121 output << indent <<
"required by tool:";
122 for (
auto const& holderName : finder.
holderNames() ) {
123 if ( holderName != this->
name() ) output <<
" " << holderName;
128 if ( conditionNode ) {
131 std::vector<EventIDRange> validRanges;
134 for (
auto& range : validRanges ) { output << indent <<
"interval of validity: " << range << std::endl; }
135 if ( validRanges.empty() ) output << indent <<
"no interval(s) of validity" << std::endl;
138 output << indent <<
"can be produced by alg(s): ";
139 for (
auto algoNode : dataNode->getProducers() ) {
140 output <<
"( " << algoNode->name() <<
" in state: " << states[algoNode->getAlgoIndex()] <<
" ) ";
146 if ( !conditionNode ) {
147 std::vector<EventSlot>* testSubSlots = &slot.
allSubSlots;
155 if ( visitor.visit( *dataNode ) ) {
156 output << indent <<
"data is available at whole-event level" << std::endl;
161 for (
auto& pair : *subSlotMap ) {
162 if ( pair.second.size() > 0 ) {
163 bool madeLine =
false;
166 for (
int slotIndex : pair.second ) {
168 EventSlot* subSlot = &testSubSlots->at( slotIndex );
169 visitor.m_slot = subSlot;
170 if ( visitor.visit( *dataNode ) ) {
174 output << indent <<
"data is available in sub-slot(s) ";
177 output << slotIndex <<
", ";
180 if ( madeLine ) { output <<
"entered from " << pair.first << std::endl; }
186 output << indent <<
"========" << std::endl;
194 visitor.
visit( *
this );
223 if ( condSvc.isValid() ) {
224 info() <<
"CondSvc found. DF precedence rules will be augmented with 'Conditions'" <<
endmsg;
232 auto& condAlgs = condSvc->condAlgs();
233 for (
const auto algo : condAlgs ) {
237 debug() <<
"Detaching condition algorithm '" << algo->name() <<
"' from the CF realm.." <<
endmsg;
239 parent->m_children.erase( std::remove( parent->m_children.begin(), parent->m_children.end(), algoNode ),
240 parent->m_children.end() );
247 warning() <<
"Algorithm '" << algo->name() <<
"' is not registered in the graph" <<
endmsg;
261 const unsigned int& recursionLevel )
const {
267 m_headNode->printState( output, slot, recursionLevel );
272 bool firstPrint =
true;
274 auto& condAlgs = condSvc->condAlgs();
275 for (
const auto algo : condAlgs ) {
290 output << std::endl <<
"Detached algorithms:" << std::endl;
292 algoNode->
printState( output, slot, recursionLevel );
301 const std::string& algoName = algo->
name();
307 verbose() <<
" Inputs of " << algoName <<
": ";
311 verbose() <<
" Outputs of " << algoName <<
": ";
325 std::sort( sortedAlgs.begin(), sortedAlgs.end(),
326 [](
const auto* a,
const auto* b ) { return a->first < b->first; } );
327 for (
auto* algo : sortedAlgs ) {
330 for (
auto output : outputs ) {
332 if ( !sc.isSuccess() ) {
333 error() <<
"Extra producer (" << algo->first <<
") for DataObject @ " << output
334 <<
" has been detected: this is not allowed." <<
endmsg;
338 dataNode->addProducerNode( algo->second.get() );
339 algo->second->addOutputDataNode( dataNode );
349 std::sort( sortedAlgs.begin(), sortedAlgs.end(),
350 [](
const auto* a,
const auto* b ) { return a->first < b->first; } );
351 for (
auto* algo : sortedAlgs ) {
360 algo->second->addInputDataNode( dataNode );
378 auto& algoName = algo->
name();
384 algoNode = itA->second.get();
388 algoNode = r.first->second.get();
402 auto parentNode = itP->second.get();
404 parentNode->addDaughterNode( algoNode );
410 ON_VERBOSE verbose() <<
"Attached AlgorithmNode '" << algo->
name() <<
"' to parent DecisionNode '" << parentName
414 error() <<
"Parent DecisionNode '" << parentName <<
"' was not found" <<
endmsg;
426 std::unique_ptr<concurrency::DataNode> dataNode;
428 dataNode = std::make_unique<concurrency::DataNode>( *
this, dataPath );
434 if ( condSvc->isRegistered( dataPath ) ) {
435 dataNode = std::make_unique<concurrency::ConditionNode>( *
this, dataPath, condSvc );
440 dataNode = std::make_unique<concurrency::DataNode>( *
this, dataPath );
459 auto& decisionHubName = decisionHubAlgo->
name();
464 decisionHubNode = itA->second.get();
468 std::make_unique<concurrency::DecisionNode>( *
this,
m_nodeCounter, decisionHubName, modeConcurrent,
469 modePromptDecision, modeOR, allPass, isInverted ) );
470 decisionHubNode = r.first->second.get();
474 allPass, isInverted ),
486 auto parentNode = itP->second.get();
487 parentNode->addDaughterNode( decisionHubNode );
493 ON_VERBOSE verbose() <<
"Attached DecisionNode '" << decisionHubName <<
"' to parent DecisionNode '" << parentName
497 error() <<
"Parent DecisionNode '" << parentName <<
"' was not found" <<
endmsg;
513 headName, std::make_unique<concurrency::DecisionNode>( *
this,
m_nodeCounter, headName, modeConcurrent,
514 modePromptDecision, modeOR, allPass, isInverted ) );
520 allPass, isInverted ),
531 auto i = std::find_if( vp.first, vp.second, [&](
const PRVertexDesc& v ) {
532 return std::visit( precedence::VertexName(), m_PRGraph[v] ) == name;
552 info() <<
"Starting ranking by data outputs .. " <<
endmsg;
555 pair.second->accept( ranker );
556 ON_DEBUG debug() <<
" ... rank of " << pair.first <<
": " << pair.second->getRank() <<
endmsg;
561 std::ostringstream ost;
567 const int& indent )
const {
568 ost << std::string( indent * 2,
' ' );
573 ost <<
node->name() <<
" [Seq] ";
576 ost << ( ( dn->
m_modeOR ) ?
" [OR] " :
"" );
577 ost << ( ( dn->
m_allPass ) ?
" [PASS] " :
"" );
581 }
else if ( an != 0 ) {
582 ost <<
node->name() <<
" [Alg] ";
584 ost <<
" [n= " << ar->cardinality() <<
"]";
585 ost << ( ( !ar->isClonable() ) ?
" [unclonable] " :
"" );
593 const char idt[] =
" ";
594 std::ostringstream ost;
596 ost <<
"\n" << idt <<
"====================================\n";
597 ost << idt <<
"Data origins and destinations:\n";
598 ost << idt <<
"====================================\n";
600 std::vector<const DataObjID*> vec;
603 std::sort( vec.begin(), vec.end(),
604 [](
const DataObjID* a,
const DataObjID* b ) { return a->fullKey() < b->fullKey(); } );
609 for (
auto algoNode :
node.getProducers() ) ost << idt <<
" " << algoNode->name() <<
"\n";
611 ost << idt <<
" V\n";
612 ost << idt <<
" o " <<
id <<
"\n";
613 ost << idt <<
" V\n";
615 for (
auto algoNode :
node.getConsumers() ) ost << idt <<
" " << algoNode->name() <<
"\n";
617 ost << idt <<
"====================================\n";
626 std::ofstream myfile;
627 myfile.open( fileName.c_str(), std::ios::app );
630 boost::dynamic_properties dp;
632 dp.property(
"Entity",
633 boost::make_transform_value_property_map(
635 return std::visit( [](
const auto& w ) {
return boost::lexical_cast<std::string>( w ); }, v );
637 boost::get( boost::vertex_bundle,
m_PRGraph ) ) );
639 auto add_prop = [&](
auto name,
auto&& vis ) {
640 dp.property(
name, boost::make_transform_value_property_map(
642 return std::visit( vis, v );
644 boost::get( boost::vertex_bundle,
m_PRGraph ) ) );
660 boost::write_graphml( myfile,
m_PRGraph, dp );
667 std::ofstream myfile;
668 myfile.open( fileName.c_str(), std::ios::app );
672 if ( !timelineSvc.
isValid() ) {
673 warning() <<
"Failed to get the TimelineSvc, timing will not be added to "
674 <<
"the task precedence trace dump" <<
endmsg;
677 std::vector<long long int> start_times;
679 for (
auto vp = vertices(
m_precTrace ); vp.first != vp.second; ++vp.first ) {
684 timelineSvc->getTimelineEvent( te );
686 long int runtime{ std::chrono::duration_cast<std::chrono::microseconds>( te.end - te.start ).count() };
690 std::chrono::duration_cast<std::chrono::nanoseconds>( te.start.time_since_epoch() ).count() };
692 if ( start != 0 ) start_times.push_back( start );
695 auto min = std::min_element( start_times.begin(), start_times.end() );
697 for (
auto vp = vertices(
m_precTrace ); vp.first != vp.second; ++vp.first ) {
701 if ( oldValue != 0 ) oldValue = oldValue - *min;
706 boost::dynamic_properties dp;
709 dp.property(
"Name", get( &AlgoTraceProps::m_name,
m_precTrace ) );
710 dp.property(
"Rank", get( &AlgoTraceProps::m_rank,
m_precTrace ) );
711 dp.property(
"Run Time (us)", get( &AlgoTraceProps::m_runtime,
m_precTrace ) );
712 dp.property(
"Start Time (ns)", get( &AlgoTraceProps::m_start,
m_precTrace ) );
721 std::string u_name = u ==
nullptr ?
"ENTRY" : u->
name();
722 std::string v_name = v->name();
729 source = itT->second;
737 source = itS->second;
750 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.
const StatusCode & 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 dumpPrecTrace(const boost::filesystem::path &, const EventSlot &slot)
dump to file the precedence trace
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.
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.
const std::string & name() const override
Retrieve name of the service.
SmartIF< ISvcLocator > & serviceLocator() const override
Retrieve pointer to service locator.
void dumpPrecRules(const boost::filesystem::path &, const EventSlot &slot)
dump to file the precedence rules
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< PRGraph >::vertex_descriptor PRVertexDesc
std::variant< AlgoProps, DecisionHubProps, DataProps, CondDataProps > VariantVertexProps
boost::graph_traits< PrecTrace >::vertex_descriptor AlgoTraceVertex
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.