20#include <boost/lexical_cast.hpp>
21#include <boost/tokenizer.hpp>
29 SmartIF<IAlgorithm> ialg;
30 Gaudi::Algorithm* alg;
31 std::set<AlgEntry const*> dependsOn;
32 std::vector<DataObjID const*> inputs;
33 std::vector<DataObjID const*> outputs;
35 friend bool operator<( AlgEntry
const& lhs, AlgEntry
const& rhs ) {
return lhs.index < rhs.index; }
37 friend bool operator==( AlgEntry
const& lhs, AlgEntry
const& rhs ) {
return lhs.index == rhs.index; }
39 AlgEntry(
size_t i, SmartIF<IAlgorithm>&& p )
40 : index{ i }, ialg{
std::move( p ) }, alg{ dynamic_cast<
Gaudi::Algorithm*>( ialg.
get() ) } {
41 if ( !alg )
throw std::runtime_error(
"algorithm pointer == nullptr???" );
44 constexpr auto gather = [](
auto&
c,
auto const& in1,
auto const& in2 ) {
45 for (
const DataObjID&
id : in1 )
c.push_back( &
id );
46 for (
const DataObjID&
id : in2 )
c.push_back( &
id );
47 constexpr auto by_key = [](
const DataObjID*
id ) {
return id->fullKey(); };
48 std::ranges::sort( c, std::less{}, by_key );
49 auto od = std::ranges::unique( c, std::equal_to{}, by_key );
50 c.erase( od.begin(), od.end() );
52 gather( outputs, alg->outputDataObjs(), alg->extraOutputDeps() );
53 gather( inputs, alg->inputDataObjs(), alg->extraInputDeps() );
57 template <std::ranges::range R>
58 requires std::common_reference_with<std::ranges::range_reference_t<R>,
const AlgEntry&>
59 void dumpDataDepsGraphFile( std::string
const& fname, R
const& algorithms ) {
62 std::size_t algoIndex = 0ul;
65 std::set<std::size_t> definedObjects;
68 std::map<std::string, std::string> indexByName;
71 std::unordered_map<std::string, std::string> output2Idx;
72 for (
const AlgEntry& entry : algorithms ) {
73 std::string algIndex =
"Alg_" + std::to_string( algoIndex );
74 indexByName[entry.alg->name()] = algIndex;
79 for (
const AlgEntry& entry : algorithms ) {
81 g.addNode( indexByName[entry.alg->name()], entry.alg->name() );
84 for (
const auto*
id : entry.inputs ) {
85 const auto [itr, inserted] = definedObjects.insert(
id->hash() );
86 std::string objIndex =
"obj_" + std::to_string(
id->hash() );
87 if ( inserted )
g.addNode( objIndex,
id->key() );
90 g.addEdge( objIndex, indexByName[entry.alg->name()] );
94 for (
const auto*
id : entry.outputs ) {
95 const auto [itr, inserted] = definedObjects.insert(
id->hash() );
96 std::string objIndex =
"obj_" + std::to_string(
id->hash() );
97 if ( inserted )
g.addNode( objIndex,
id->key() );
100 g.addEdge( indexByName[entry.alg->name()], objIndex );
105 struct AlgorithmRepr {
106 const Gaudi::Algorithm& parent;
108 friend std::ostream&
operator<<( std::ostream& s,
const AlgorithmRepr& a ) {
111 if ( a.parent.
name() != typ )
s <<
"/" << a.parent.
name();
117 template <
typename T>
118 std::vector<const T*> sorted_(
const std::set<T*>& s ) {
119 std::vector<const T*>
v{
s.begin(),
s.end() };
120 std::sort(
v.begin(),
v.end(), [](
const auto* lhs,
const auto* rhs ) { return *lhs < *rhs; } );
134 using extends::extends;
137 const std::vector<std::string>& stoppers = {} )
const override;
139 const std::vector<std::string>& stoppers = {} )
const override;
148 "Attribute any unmet input dependencies to this Algorithm" };
150 this,
"DataProducers", {},
"List of algorithms to be used to resolve data dependencies" };
153 "Name of the output file (.dot, .md or .graphml extensions "
154 "allowed) containing the data dependency graph. "
155 "If empty, no graph is dumped" };
157 std::map<std::string, AlgEntry>
166 std::map<DataObjID, AlgEntry const*>
mapProducers( std::map<std::string, AlgEntry>& algorithms )
const;
170 void visit( AlgEntry
const& alg, std::vector<std::string>
const& stoppers, std::vector<Gaudi::Algorithm*>& sorted,
171 std::vector<bool>& visited, std::vector<bool>& visiting )
const;
182 std::ranges::for_each(
m_algorithms | std::ranges::views::transform( [](
const auto& entry ) ->
decltype(
auto ) {
183 return entry.second.alg;
185 std::ranges::views::filter( [](
const auto* alg ) {
return alg->cardinality() > 0; } ),
187 this->
warning() <<
"non-reentrant algorithm: " << AlgorithmRepr{ *alg } <<
endmsg;
191 debug() <<
"Available DataProducers:\n";
192 std::ranges::for_each(
m_algorithms | std::ranges::views::transform( [](
const auto& entry ) ->
decltype(
auto ) {
193 return entry.second.alg;
196 this->
debug() <<
" " << AlgorithmRepr{ *alg } <<
" " << alg->outputDataObjs() <<
" "
197 << alg->extraOutputDeps() <<
endmsg;
213 ss = algEntry.alg->sysStart();
228 ss = algEntry.alg->sysStop();
239 algEntry.alg->sysFinalize().ignore( );
245std::map<std::string, AlgEntry>
247 std::map<std::string, AlgEntry> algorithms;
252 for (
const std::string& item : names ) {
258 myIAlg = createAlgorithm( *appMgr, tn.
type(), tn.
name() );
266 throw GaudiException{
"Failed to create " + boost::lexical_cast<std::string>( item ), __func__,
273 throw GaudiException{
"Failed to initialize " + boost::lexical_cast<std::string>( item ), __func__,
277 algorithms.emplace( tn.
name(), AlgEntry{ index++, std::move( myIAlg ) } );
283std::map<DataObjID, AlgEntry const*>
286 debug() <<
"Data Dependencies for Algorithms:";
289 for (
const auto*
id : entry.inputs ) {
debug() <<
"\n o INPUT " <<
id->key(); }
290 for (
const auto*
id : entry.outputs ) {
debug() <<
"\n o OUTPUT " <<
id->key(); }
302 std::map<DataObjID, const AlgEntry*> producers;
303 for (
auto& [
name, alg] : algorithms ) {
304 for (
auto id : alg.outputs ) {
305 auto r = producers.emplace( *
id, &alg );
307 throw GaudiException(
"multiple algorithms declare " + id->key() +
" as output (" +
name +
" and " +
308 producers[*
id]->alg->name() +
" at least). This is not allowed",
315 for (
auto& [
name, algEntry] : algorithms ) {
316 for (
const DataObjID* idp : algEntry.inputs ) {
318 auto iproducer = producers.find(
id );
319 if ( iproducer != producers.end() ) {
320 algEntry.dependsOn.insert( iproducer->second );
322 std::ostringstream error_message;
323 error_message <<
"\nUnknown requested input by " << AlgorithmRepr{ *( algEntry.alg ) } <<
" : "
324 << std::quoted(
id.key(),
'\'' ) <<
".\n";
325 error_message <<
"You can set the OutputLevel of HiveDataBrokerSvc to DEBUG to get a list of inputs and "
326 "outputs of every registered algorithm.\n";
340 std::vector<Gaudi::Algorithm*>& sorted, std::vector<bool>& visited,
341 std::vector<bool>& visiting )
const {
344 if ( visited[alg.index] ) {
return; }
347 if ( std::none_of( std::begin( stoppers ), std::end( stoppers ),
348 [alg](
auto& stopper ) {
return alg.alg->name() == stopper; } ) ) {
349 visiting[alg.index] =
true;
350 for (
auto* dep : sorted_( alg.dependsOn ) ) {
visit( *dep, stoppers, sorted, visited, visiting ); }
351 visiting[alg.index] =
false;
354 visited[alg.index] =
true;
355 sorted.push_back( alg.alg );
358std::vector<Gaudi::Algorithm*>
360 const std::vector<std::string>& stoppers )
const {
361 std::vector<Gaudi::Algorithm*> result;
363 std::vector<const AlgEntry*> deps;
364 deps.reserve( requested.size() );
367 for (
const auto&
id : requested ) {
371 deps.push_back( i->second );
374 std::sort( deps.begin(), deps.end(), [](
auto const* lhs,
auto const* rhs ) { return *lhs < *rhs; } );
375 deps.erase( std::unique( deps.begin(), deps.end(), [](
auto const& lhs,
auto const& rhs ) { return *lhs == *rhs; } ),
380 for (
auto* alg : deps ) {
visit( *alg, stoppers, result, visited, visiting ); }
384std::vector<Gaudi::Algorithm*>
386 const std::vector<std::string>& stoppers )
const {
387 std::vector<Gaudi::Algorithm*> result;
391 throw GaudiException{
"No algorithm with name " + requested.
name() +
" in DataProducers. Type is " +
392 ( requested.
haveType() ? requested.
type() :
"not specified" ),
395 auto const& alg = it->second;
396 if ( requested.
haveType() && alg.alg->type() != requested.
type() ) {
397 error() <<
"requested " << requested <<
" but have matching name with different type: " << alg.alg->type()
400 assert( alg.alg !=
nullptr );
404 visit( alg, stoppers, result, visited, visiting );
407 debug() << std::endl <<
"requested " << requested <<
" returning " << std::endl <<
" ";
409 debug(), result,
",\n ",
410 [](
auto& os,
const Gaudi::Algorithm* a ) ->
decltype(
auto ) {
return os << AlgorithmRepr{ *a }; } );
std::ostream & operator<<(std::ostream &s, AlgsExecutionStates::State x)
Streaming of State values.
bool operator==(const GaudiUtils::Allocator< T1 > &, const GaudiUtils::Allocator< T2 > &)
std::unordered_set< DataObjID, DataObjID_Hasher > DataObjIDColl
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
#define DECLARE_COMPONENT(type)
bool operator<(backwards_compatibility_hack_time_timespan, backwards_compatibility_hack_time_timespan)
MsgStream & error() const
shortcut for the method msgStream(MSG::ERROR)
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)
MSG::Level msgLevel() const
Base class from which all concrete algorithm classes should be derived.
const std::string & name() const override
The identifying name of the algorithm object.
utilities to dump graphs in different formats
Implementation of property with value of concrete type.
Helper class to parse a string of format "type/name".
const std::string & type() const
const std::string & name() const
Define general base for Gaudi exception.
StatusCode initialize() override
std::map< std::string, AlgEntry > instantiateAndInitializeAlgorithms(const std::vector< std::string > &names) const
Gaudi::Property< std::vector< std::string > > m_producers
std::map< std::string, AlgEntry > m_algorithms
StatusCode stop() override
Gaudi::Property< std::string > m_dataDepsGraphFile
StatusCode finalize() override
Gaudi::Property< std::string > m_dataLoader
std::map< DataObjID, AlgEntry const * > mapProducers(std::map< std::string, AlgEntry > &algorithms) const
void visit(AlgEntry const &alg, std::vector< std::string > const &stoppers, std::vector< Gaudi::Algorithm * > &sorted, std::vector< bool > &visited, std::vector< bool > &visiting) const
Implements DFS topological sorting.
std::vector< Gaudi::Algorithm * > algorithmsRequiredFor(const DataObjIDColl &requested, const std::vector< std::string > &stoppers={}) const override
StatusCode start() override
std::map< DataObjID, AlgEntry const * > m_dependencies
The IAlgManager is the interface implemented by the Algorithm Factory in the Application Manager to s...
virtual StatusCode createAlgorithm(const std::string &algtype, const std::string &algname, IAlgorithm *&alg, bool managed=false, bool checkIfExists=true)=0
Create an instance of a algorithm type that has been declared beforehand and assigns to it a name.
The IAlgorithm is the interface implemented by the Algorithm base class.
StatusCode finalize() override
const std::string & name() const override
Retrieve name of the service.
StatusCode stop() override
SmartIF< IFace > service(const std::string &name, bool createIf=true) const
StatusCode start() override
StatusCode initialize() override
Small smart pointer class with automatic reference counting for IInterface.
This class is used for returning status codes from appropriate routines.
StatusCode andThen(F &&f, ARGS &&... args) const
Chain code blocks making the execution conditional a success result.
constexpr static const auto FAILURE
Base class used to extend a class implementing other interfaces.
get
decorate the vector of properties
Stream & ostream_joiner(Stream &os, Iterator first, Iterator last, Separator sep, OutputElement output=OutputElement{})
GAUDI_API const std::string typeinfoName(const std::type_info &)
Get platform independent information about the class type.