ATLAS Offline Software
Loading...
Searching...
No Matches
GlobalSim::GraphSvc Class Reference

The GraphSvc can be used to create an execution graph of the global simulation part of the job. More...

#include <GraphSvc.h>

Inheritance diagram for GlobalSim::GraphSvc:
Collaboration diagram for GlobalSim::GraphSvc:

Public Member Functions

virtual StatusCode initialize () override
 Initialise.
virtual StatusCode start () override
 Start - do graph calculation here, to ensure EventLoopMgr initialized already.
virtual StatusCode finalize () override
 Finalise.

Private Attributes

StringProperty m_fileName {this,"FileName","graph.dot","Output file"}
StringProperty m_topSequence {this,"SequenceNameFilter","GlobalSim","Regex of sequence names to include"}
ServiceHandle< IAlgResourcePool > m_algResourcePool

Detailed Description

The GraphSvc can be used to create an execution graph of the global simulation part of the job.

Definition at line 17 of file GraphSvc.h.

Member Function Documentation

◆ finalize()

StatusCode GlobalSim::GraphSvc::finalize ( )
overridevirtual

Finalise.

Definition at line 172 of file GraphSvc.cxx.

172 {
173 return StatusCode::SUCCESS;
174
175 }

◆ initialize()

StatusCode GlobalSim::GraphSvc::initialize ( )
overridevirtual

Initialise.

Definition at line 21 of file GraphSvc.cxx.

21 {
22 return StatusCode::SUCCESS;
23 }

◆ start()

StatusCode GlobalSim::GraphSvc::start ( )
overridevirtual

Start - do graph calculation here, to ensure EventLoopMgr initialized already.

Definition at line 25 of file GraphSvc.cxx.

25 {
26
27 std::function<void(IAlgorithm*,std::set<IAlgorithm*>&,bool)> func;
28
29 std::regex sequenceNameRegex( m_topSequence.value() );
30
31 // locate the desired algs ...
32 func = [&](IAlgorithm* alg, std::set<IAlgorithm*>& thealgs, bool isAdding) {
33 isAdding = (isAdding || std::regex_search( std::string(alg->nameKey()) , sequenceNameRegex) ); // activate adding when get to target
34 if(isAdding) {
35 thealgs.insert(alg);
36 }
37 if(auto seq = dynamic_cast<Gaudi::Sequence*>( alg )) {
38 auto subalgs = seq->subAlgorithms();
39 for(auto thisAlg : *subalgs) {
40 func(thisAlg,thealgs,isAdding);
41 }
42 }
43 };
44
45 // Get the list of algorithms
46 const std::list<IAlgorithm*>& algos = m_algResourcePool->getTopAlgList();
47 std::set<IAlgorithm*> subalgs;
48 for ( IAlgorithm* ialgoPtr : algos ) {
49 func(ialgoPtr,subalgs,false);
50 }
51
52
53 DataObjIDColl globalInp, globalOutp;
54 std::map<std::string, DataObjIDColl> algosOutputDependenciesMap;
55 std::map<std::string, DataObjIDColl> algosInputDependenciesMap;
56
57 for ( IAlgorithm* ialgoPtr : subalgs ) {
58 if(ialgoPtr->isSequence()) continue; // don't look at sequences, shouldn't have any inputs/outputs
59
60 Gaudi::Algorithm* algoPtr = dynamic_cast<Gaudi::Algorithm*>( ialgoPtr );
61 if ( !algoPtr ) continue;
62 DataObjIDColl algoOutputs;
63 for ( const auto & id : algoPtr->outputDataObjs() ) {
64 globalOutp.insert( id );
65 algoOutputs.insert( id );
66 }
67
68
69
70 DataObjIDColl i1, i2;
71 DHHVisitor avis( i1, i2 );
72 algoPtr->acceptDHVisitor( &avis );
73
74 DataObjIDColl algoDependencies;
75 for ( const DataObjID& id : algoPtr->inputDataObjs() ) {
76 algoDependencies.insert( id );
77 globalInp.insert( id );
78 }
79
80 std::string algoName = ialgoPtr->nameKey();
81 if(ialgoPtr->type()!= algoName) {
82 algoName = ialgoPtr->type() + "/" + algoName;
83 }
84
85 algosInputDependenciesMap[algoName] = std::move(algoDependencies);
86 algosOutputDependenciesMap[algoName] = std::move(algoOutputs);
87
88 }
89
90
91 ATH_MSG_INFO("Creating " << m_fileName.value());
92 std::ofstream stream{ m_fileName, std::ofstream::out };
93 stream << "digraph datadeps {\n rankdir=\"LR\";\n"; // left-to-right graph
94
95 auto addNode = [&](std::string_view id, std::string_view name, std::string_view shape="box" ) {
96 stream << " " << id << " [label=\"" << name << "\";shape=" << shape << "];\n"; // adds a node
97 };
98 auto addEdge = [&](std::string_view srcId, std::string_view tgtId, std::string_view label ) {
99 stream << " " << srcId << " -> " << tgtId << " [label=\"" << label << "\"];\n"; // adds an edge
100 };
101
102 // find all inputs that do not have an output. These will be our 'starting nodes' of shape='plaintext'
103 std::map<std::string,std::pair<std::set<std::string>,std::set<std::string>>> deps;
104
105 // key is dep name, value is pair of sets, first are "producers" of dep, second a "consumers" of dep
106 // if has no producer, is a global input. if has no consumer, is a global output.
107
108 for ( const auto& [algName, ideps] : algosInputDependenciesMap ) {
109 for (const auto &dep: ideps) {
110 deps[dep.key()].second.insert(algName); // alg is a consumer
111 }
112 }
113 for ( const auto& [algName, odeps] : algosOutputDependenciesMap ) {
114 for (const auto &dep: odeps) {
115 deps[dep.key()].first.insert(algName); // alg is a producer
116 }
117 }
118
119 std::size_t algoIndex = 0ul;
120 std::map<std::string,std::string> keyToName;
121 std::string inputs,outputs;
122 // start by creating nodes of global inputs and outputs
123 for( auto& [dep, pcs] : deps) {
124 auto& [producers,consumers] = pcs;
125 if(producers.empty()) {
126 std::string algIndex = "Input_" + std::to_string( algoIndex );
127 addNode( algIndex, dep, "plaintext" );
128 keyToName[dep] = algIndex;
129 algoIndex++;
130 producers.insert(dep); // its a self-producer
131 inputs += algIndex + "; ";
132 } else if(consumers.empty()) {
133 std::string algIndex = "Output_" + std::to_string( algoIndex );
134 addNode( algIndex, dep, "plaintext" );
135 keyToName[dep] = algIndex;
136 algoIndex++;
137 consumers.insert(dep); // its a self-consumer
138 outputs += algIndex + "; ";
139 }
140 }
141 // create nodes of all algorithms
142 for ( const auto& [algName, ideps] : algosInputDependenciesMap ) {
143 std::string algIndex = "Alg_" + std::to_string( algoIndex );
144 addNode( algIndex, algName, "box" );
145 keyToName[algName] = std::move(algIndex);
146 algoIndex++;
147 }
148 // now go through deps and create link from every producer to every consumer
149 for( const auto& [dep, pcs] : deps) {
150 auto& [producers,consumers] = pcs;
151 for(auto& producer : producers) {
152 for(auto& consumer: consumers) {
153 addEdge(keyToName.at(producer),keyToName.at(consumer),dep!=producer && dep!=consumer ? dep : " ");
154 }
155 }
156 }
157
158 if(!inputs.empty()) {
159 stream << " { rank = same; " << inputs << "}\n";
160 }
161 if(!outputs.empty()) {
162 stream << " { rank = same; " << outputs << "}\n";
163 }
164
165 stream << "}\n";
166 stream.close();
167
168 return StatusCode::SUCCESS;
169
170 }
#define ATH_MSG_INFO(x)
StringProperty m_fileName
Definition GraphSvc.h:32
StringProperty m_topSequence
Definition GraphSvc.h:33
ServiceHandle< IAlgResourcePool > m_algResourcePool
Definition GraphSvc.h:35
std::string label(const std::string &format, int i)
Definition label.h:19
unsigned long ul
const std::string & algName(ID id)
Converts a JetAlgorithmType::ID into a string.

Member Data Documentation

◆ m_algResourcePool

ServiceHandle<IAlgResourcePool> GlobalSim::GraphSvc::m_algResourcePool
private
Initial value:
{this,"AlgResourcePool","AlgResourcePool",
"Algorithm resource pool service."}

Definition at line 35 of file GraphSvc.h.

35 {this,"AlgResourcePool","AlgResourcePool",
36 "Algorithm resource pool service."};

◆ m_fileName

StringProperty GlobalSim::GraphSvc::m_fileName {this,"FileName","graph.dot","Output file"}
private

Definition at line 32 of file GraphSvc.h.

32{this,"FileName","graph.dot","Output file"};

◆ m_topSequence

StringProperty GlobalSim::GraphSvc::m_topSequence {this,"SequenceNameFilter","GlobalSim","Regex of sequence names to include"}
private

Definition at line 33 of file GraphSvc.h.

33{this,"SequenceNameFilter","GlobalSim","Regex of sequence names to include"};

The documentation for this class was generated from the following files: