20 #include <boost/lexical_cast.hpp>
21 #include <boost/tokenizer.hpp>
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; }
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 dumpGraphFile( std::string
const& fname, R
const&
algorithms ) {
63 for (
const AlgEntry& entry :
algorithms ) {
g.addNode( entry.alg->name(), std::to_string( entry.index ) ); }
66 std::unordered_map<std::string, size_t> output2Idx;
68 for (
const auto*
id : entry.outputs ) { output2Idx[
id->key()] = entry.index; }
73 for (
const auto*
id : entry.inputs ) {
74 g.addEdge( entry.alg->name(), std::to_string( entry.index ),
id->key(), std::to_string( output2Idx[
id->key()] ),
80 struct AlgorithmRepr {
83 friend std::ostream&
operator<<( std::ostream&
s,
const AlgorithmRepr& a ) {
86 if ( a.parent.name() != typ )
s <<
"/" << a.parent.name();
93 std::vector<const T*> sorted_(
const std::set<T*>&
s ) {
94 std::vector<const T*>
v{
s.begin(),
s.end() };
95 std::sort(
v.begin(),
v.end(), [](
const auto* lhs,
const auto* rhs ) { return *lhs < *rhs; } );
109 using extends::extends;
112 const std::vector<std::string>& stoppers = {} )
const override;
114 const std::vector<std::string>& stoppers = {} )
const override;
123 "Attribute any unmet input dependencies to this Algorithm" };
125 this,
"DataProducers", {},
"List of algorithms to be used to resolve data dependencies" };
128 this,
"DataDepsGraphFile",
"",
129 "Name of the output file (.dot or .md extensions allowed) containing the data dependency graph. If empty, no "
132 std::map<std::string, AlgEntry>
145 void visit( AlgEntry
const&
alg, std::vector<std::string>
const& stoppers, std::vector<Gaudi::Algorithm*>& sorted,
146 std::vector<bool>& visited, std::vector<bool>& visiting )
const;
154 m_algorithms = instantiateAndInitializeAlgorithms( m_producers );
157 std::ranges::for_each( m_algorithms | std::ranges::views::transform( [](
const auto& entry ) -> decltype(
auto ) {
158 return entry.second.alg;
160 std::ranges::views::filter( [](
const auto*
alg ) {
return alg->cardinality() > 0; } ),
162 this->warning() <<
"non-reentrant algorithm: " << AlgorithmRepr{ *
alg } <<
endmsg;
166 debug() <<
"Available DataProducers:\n";
167 std::ranges::for_each( m_algorithms | std::ranges::views::transform( [](
const auto& entry ) -> decltype(
auto ) {
168 return entry.second.alg;
171 this->debug() <<
" " << AlgorithmRepr{ *
alg } <<
" " <<
alg->outputDataObjs() <<
" "
177 m_dependencies = mapProducers( m_algorithms );
188 ss = algEntry.alg->sysStart();
190 error() <<
"Unable to start Algorithm: " <<
name <<
endmsg;
203 ss = algEntry.alg->sysStop();
205 error() <<
"Unable to stop Algorithm: " <<
name <<
endmsg;
214 algEntry.alg->sysFinalize().
ignore( );
220 std::map<std::string, AlgEntry>
225 auto appMgr = service<IAlgManager>(
"ApplicationMgr" );
227 for (
const std::string& item : names ) {
241 throw GaudiException{
"Failed to create " + boost::lexical_cast<std::string>( item ), __func__,
248 throw GaudiException{
"Failed to initialize " + boost::lexical_cast<std::string>( item ), __func__,
252 algorithms.emplace( tn.
name(), AlgEntry{ index++, std::move( myIAlg ) } );
258 std::map<DataObjID, AlgEntry const*>
261 debug() <<
"Data Dependencies for Algorithms:";
263 debug() <<
"\n " <<
name <<
" :";
264 for (
const auto*
id : entry.inputs ) { debug() <<
"\n o INPUT " <<
id->key(); }
265 for (
const auto*
id : entry.outputs ) { debug() <<
"\n o OUTPUT " <<
id->key(); }
277 std::map<DataObjID, const AlgEntry*> producers;
279 for (
auto id :
alg.outputs ) {
280 auto r = producers.emplace( *
id, &
alg );
282 throw GaudiException(
"multiple algorithms declare " +
id->key() +
" as output (" +
name +
" and " +
283 producers[*
id]->alg->name() +
" at least). This is not allowed",
291 for (
const DataObjID* idp : algEntry.inputs ) {
293 auto iproducer = producers.find(
id );
294 if ( iproducer != producers.end() ) {
295 algEntry.dependsOn.insert( iproducer->second );
297 std::ostringstream error_message;
298 error_message <<
"\nUnknown requested input by " << AlgorithmRepr{ *( algEntry.alg ) } <<
" : "
299 << std::quoted(
id.
key(),
'\'' ) <<
".\n";
300 error_message <<
"You can set the OutputLevel of HiveDataBrokerSvc to DEBUG to get a list of inputs and "
301 "outputs of every registered algorithm.\n";
315 std::vector<Gaudi::Algorithm*>& sorted, std::vector<bool>& visited,
316 std::vector<bool>& visiting )
const {
319 if ( visited[
alg.index] ) {
return; }
323 [
alg](
auto& stopper ) {
return alg.alg->name() == stopper; } ) ) {
324 visiting[
alg.index] =
true;
325 for (
auto* dep : sorted_(
alg.dependsOn ) ) {
visit( *dep, stoppers, sorted, visited, visiting ); }
326 visiting[
alg.index] =
false;
329 visited[
alg.index] =
true;
330 sorted.push_back(
alg.alg );
333 std::vector<Gaudi::Algorithm*>
335 const std::vector<std::string>& stoppers )
const {
336 std::vector<Gaudi::Algorithm*> result;
338 std::vector<const AlgEntry*> deps;
339 deps.reserve( requested.size() );
342 for (
const auto&
id : requested ) {
346 deps.push_back( i->second );
349 std::sort( deps.begin(), deps.end(), [](
auto const* lhs,
auto const* rhs ) { return *lhs < *rhs; } );
350 deps.erase( std::unique( deps.begin(), deps.end(), [](
auto const& lhs,
auto const& rhs ) { return *lhs == *rhs; } ),
355 for (
auto*
alg : deps ) {
visit( *
alg, stoppers, result, visited, visiting ); }
359 std::vector<Gaudi::Algorithm*>
361 const std::vector<std::string>& stoppers )
const {
362 std::vector<Gaudi::Algorithm*> result;
366 throw GaudiException{
"No algorithm with name " + requested.
name() +
" in DataProducers. Type is " +
367 ( requested.
haveType() ? requested.
type() :
"not specified" ),
370 auto const&
alg = it->second;
372 error() <<
"requested " << requested <<
" but have matching name with different type: " <<
alg.alg->type()
375 assert(
alg.alg !=
nullptr );
379 visit(
alg, stoppers, result, visited, visiting );
382 debug() << std::endl <<
"requested " << requested <<
" returning " << std::endl <<
" ";
384 debug(), result,
",\n ",
385 [](
auto& os,
const Gaudi::Algorithm* a ) -> decltype(
auto ) {
return os << AlgorithmRepr{ *a }; } );
386 debug() << std::endl <<
endmsg;