ATLAS Offline Software
Loading...
Searching...
No Matches
GraphSvc.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
5#include "GraphSvc.h"
6#include "GaudiKernel/Algorithm.h"
7#include "Gaudi/Sequence.h"
8#include "GaudiKernel/DataHandleHolderVisitor.h"
9
10#include <fstream>
11#include <regex>
12#include <functional>
13#include <string>
14#include <string_view>
15#include <set>
16#include <list>
17#include <map>
18
19namespace GlobalSim {
20
21 StatusCode GraphSvc::initialize() {
22 return StatusCode::SUCCESS;
23 }
24
25 StatusCode GraphSvc::start() {
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", std::string_view textcol="" ) {
96 stream << " " << id << " [label=\"" << name << "\"";
97 if(!textcol.empty()) stream << ", fontcolor=\"" << textcol << "\"";
98 stream << ";shape=" << shape << "];\n"; // adds a node
99 };
100 auto addEdge = [&](std::string_view srcId, std::string_view tgtId, std::string_view label ) {
101 stream << " " << srcId << " -> " << tgtId << " [label=\"" << label << "\"];\n"; // adds an edge
102 };
103
104 // find all inputs that do not have an output. These will be our 'starting nodes' of shape='plaintext'
105 std::map<std::string,std::pair<std::set<std::string>,std::set<std::string>>> deps;
106
107 // key is dep name, value is pair of sets, first are "producers" of dep, second a "consumers" of dep
108 // if has no producer, is a global input. if has no consumer, is a global output.
109
110 std::map<std::string,std::string> inputTypes;
111
112 for ( const auto& [algName, ideps] : algosInputDependenciesMap ) {
113 for (const auto &dep: ideps) {
114 deps[dep.key()].second.insert(algName); // alg is a consumer
115 // store classes of inputs
116 inputTypes[dep.key()] = dep.className();
117 }
118 }
119 for ( const auto& [algName, odeps] : algosOutputDependenciesMap ) {
120 for (const auto &dep: odeps) {
121 deps[dep.key()].first.insert(algName); // alg is a producer
122 }
123 }
124
125 std::size_t algoIndex = 0ul;
126 std::map<std::string,std::string> keyToName;
127 std::string inputs,outputs;
128 // start by creating nodes of global inputs and outputs
129 for( auto& [dep, pcs] : deps) {
130 auto& [producers,consumers] = pcs;
131 if(producers.empty()) {
132 std::string algIndex = "Input_" + std::to_string( algoIndex );
133 addNode( algIndex, inputTypes[dep]+"/"+dep.substr(dep.find("+")+1), "plaintext", (dep.find("ConditionStore")==0) ? "blue" : "" );
134 keyToName[dep] = algIndex;
135 algoIndex++;
136 producers.insert(dep); // its a self-producer
137 inputs += algIndex + "; ";
138 } else if(consumers.empty()) {
139 std::string algIndex = "Output_" + std::to_string( algoIndex );
140 addNode( algIndex, dep.substr(dep.find("+")+1), "plaintext" );
141 keyToName[dep] = algIndex;
142 algoIndex++;
143 consumers.insert(dep); // its a self-consumer
144 outputs += algIndex + "; ";
145 }
146 }
147 // create nodes of all algorithms
148 for ( const auto& [algName, ideps] : algosInputDependenciesMap ) {
149 std::string algIndex = "Alg_" + std::to_string( algoIndex );
150 addNode( algIndex, algName, "box" );
151 keyToName[algName] = std::move(algIndex);
152 algoIndex++;
153 }
154 // now go through deps and create link from every producer to every consumer
155 for( const auto& [dep, pcs] : deps) {
156 auto& [producers,consumers] = pcs;
157 for(auto& producer : producers) {
158 for(auto& consumer: consumers) {
159 addEdge(keyToName.at(producer),keyToName.at(consumer),dep!=producer && dep!=consumer ? (inputTypes[dep]+"/"+dep.substr(dep.find("+")+1)) : " ");
160 }
161 }
162 }
163
164 if(!inputs.empty()) {
165 stream << " { rank = same; " << inputs << "}\n";
166 }
167 if(!outputs.empty()) {
168 stream << " { rank = same; " << outputs << "}\n";
169 }
170
171 stream << "}\n";
172 stream.close();
173
174 return StatusCode::SUCCESS;
175
176 }
177
178 StatusCode GraphSvc::finalize() {
179
180 ATH_MSG_INFO("To view graph run: dot -Teps " << m_fileName.value() << " -o graph.eps; gv graph.eps &");
181
182 return StatusCode::SUCCESS;
183
184 }
185
186}
187
#define ATH_MSG_INFO(x,...)
virtual StatusCode start() override
Start - do graph calculation here, to ensure EventLoopMgr initialized already.
Definition GraphSvc.cxx:25
virtual StatusCode initialize() override
Initialise.
Definition GraphSvc.cxx:21
StringProperty m_fileName
Definition GraphSvc.h:32
virtual StatusCode finalize() override
Finalise.
Definition GraphSvc.cxx:178
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
AlgTool to read in LArStripNeighborhoods, and run the BDT Algorithm.
Definition BitSpec.h:23