ATLAS Offline Software
Loading...
Searching...
No Matches
DynamicDataHelper.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
3*/
6#include "GaudiKernel/AlgTool.h"
7#include "GaudiKernel/IClassIDSvc.h"
8
9#include <string_view>
10#include <sstream>
11
12
13namespace Ath {
14 namespace {
15 void insertHandles(DataObjIDPtrColl &handle_set, const std::vector<Gaudi::DataHandle*> &new_handles) {
16 for( const Gaudi::DataHandle*handle : new_handles) {
17 handle_set.insert( &handle->fullKey() );
18 }
19 }
20
21 bool msgLvl(const MsgStream &out, const MSG::Level level) {
22 return level<= out.level();
23 }
24 }
25
26 StatusCode DynamicDataHelper::addExtraDependencies(IClassIDSvc &clid_svc, std::vector<std::string> &undeclared_output_data, MsgStream &out) {
27 std::stringstream error;
28 if (!m_extraOutputIDs.empty()) {
29 out << MSG::FATAL << "Logic erroor. Already added some extra output data IDs. This method can only be called once." << endmsg;
30 return StatusCode::FAILURE;
31 }
32 m_extraOutputIDs.reserve( undeclared_output_data.size() );
33 for(const std::string &type_and_name : undeclared_output_data) {
34 std::string::size_type pos = type_and_name.find('/');
35 if (pos == std::string::npos) {
36 error << " " << type_and_name;
37 }
38 else {
39 std::string_view type_name(type_and_name.data(), pos);
40 std::string_view var_name(&(type_and_name.data()[pos+1]), type_and_name.size()-pos-1);
41 CLID clid;
42 if (clid_svc.getIDOfTypeName(std::string(type_name), clid).isFailure() ) {
43 // out << MSG::FATAL << " Failed to get CLID for " << type_name << endmsg;
44 // return StatusCode::FAILURE;
45 error << " no clid: " << type_name;
46 }
47 else {
48 m_extraOutputIDs.push_back( DataObjID(clid, std::string(var_name)) );
49 if (msgLvl(out,MSG::VERBOSE)) {
50 out << MSG::VERBOSE << "DEBUG add extra dependency " << type_name << " / " << var_name << " -> " << clid << endmsg;
51 }
52 }
53 }
54 }
55 if (!error.str().empty()) {
56 out << MSG::FATAL << "Invaid alements in property " << error.str().c_str() << endmsg;
57 return StatusCode::FAILURE;
58 }
59 for (const DataObjID &id : m_extraOutputIDs ) {
60 m_outputHandles.insert( &id );
61 }
62 return StatusCode::SUCCESS;
63 }
64
65 void DynamicDataHelper::gatherDataHandlesAndDynamicConsumers(const std::string &/*parent_name*/, Gaudi::Algorithm *theAlgorithm) {
66 // |> debugging
67 auto algorithm_visitor =
68 [this](Gaudi::Algorithm *an_alg) {
69 IDynamicDataConsumer *a_dyn_data_consumer=dynamic_cast<IDynamicDataConsumer *>(an_alg);
70 if (a_dyn_data_consumer) {
71 std::vector<Gaudi::Algorithm *> &alg_list = m_dynDataConsumer[a_dyn_data_consumer];
72 if (std::find(alg_list.begin(),alg_list.end(),an_alg)==alg_list.end()) {
73 alg_list.push_back(an_alg);
74 }
75 }
76 // have to collect input and output handles because the sequence will only collect them after initialize
77 insertHandles(m_inputHandles, an_alg->inputHandles());
78 insertHandles(m_outputHandles, an_alg->outputHandles());
79 std::vector<IAlgTool *> &tools ATLAS_THREAD_SAFE
80 = const_cast< std::vector<IAlgTool *> &>(const_cast<const Gaudi::Algorithm *>(an_alg)->tools());
81 // |> debugging
82 auto tool_visitor = [this, an_alg](IAlgTool *alg_tool) {
83 IDynamicDataConsumer *a_dyn_data_consumer=dynamic_cast<IDynamicDataConsumer *>(alg_tool);
84 if (a_dyn_data_consumer) {
85 std::vector<Gaudi::Algorithm *> &alg_list = m_dynDataConsumer[a_dyn_data_consumer];
86 if (std::find(alg_list.begin(),alg_list.end(),an_alg)==alg_list.end()) {
87 alg_list.push_back(an_alg);
88 }
89 }
90 if (auto* tool_impl = dynamic_cast<AlgTool*>( alg_tool ); tool_impl) {
91 insertHandles(m_inputHandles, tool_impl->inputHandles());
92 insertHandles(m_outputHandles, tool_impl->outputHandles());
93 }
94 };
95 xGaudi::ToolVisitor::visit( tools,tool_visitor);
96 };
97 xGaudi::AlgorithmVisitor::visit({theAlgorithm},algorithm_visitor);
98 }
99
100 void DynamicDataHelper::updateDataNeeds(unsigned int max_pass,
101 MsgStream &out) {
102 if (msgLvl(out,MSG::VERBOSE)) out << MSG::VERBOSE << "Allow dynamic data consumers to update their data dependencies." << endmsg;
103 std::vector<const DataObjID *> all_input_data;
104 std::vector<const DataObjID *> all_output_data;
105 all_input_data.insert( all_input_data.end(), m_inputHandles.begin(), m_inputHandles.end());
106 all_output_data.insert( all_output_data.end(), m_outputHandles.begin(), m_outputHandles.end());
107
108 std::vector<const DataObjID *> new_input_data;
109 std::vector<const DataObjID *> new_output_data;
110 unsigned int pass_i=max_pass;
111 unsigned last_out_size=new_output_data.size();
112 for (; --pass_i>0 && updateDataNeeds(all_input_data, all_output_data, new_input_data, new_output_data,out); ) {
113 if (last_out_size == new_output_data.size() ) break;
114 last_out_size=new_output_data.size();
115 };
116 if (last_out_size != new_output_data.size()) {
117 out << MSG::WARNING << "Not iterating any further, although after " << max_pass << " iterations there are still algorithms which updated their data needs. " << endmsg;
118 }
119 }
120
121 bool DynamicDataHelper::updateDataNeeds(const std::vector<const DataObjID *> &input_data_in,
122 const std::vector<const DataObjID *> &output_data_in,
123 std::vector<const DataObjID *> &input_data_out,
124 std::vector<const DataObjID *> &output_data_out,
125 MsgStream &out) {
126 bool updated=false;
127 if (msgLvl(out,MSG::VERBOSE)) {
128 out<< MSG::VERBOSE << " inputs:";
129 for (const DataObjID *id : input_data_in) {
130 out << " " << *id ;
131 }
132 out << endmsg;
133 out << MSG::VERBOSE << " outputs:";
134 for (const DataObjID *id : output_data_in) {
135 out << " " << *id ;
136 }
137 out << endmsg;
138 }
139 for (std::pair<IDynamicDataConsumer * const,std::vector<Gaudi::Algorithm *> > &dyn_data_consumer : m_dynDataConsumer ) {
140 std::vector<Gaudi::DataHandle *> tmp_new_input_handles;
141 std::vector<Gaudi::DataHandle *> tmp_new_output_handles;
142 bool ret = dyn_data_consumer.first->updateDataNeeds(input_data_in, output_data_in, tmp_new_input_handles, tmp_new_output_handles);
143 if (msgLvl(out,MSG::VERBOSE)) {
144 out << MSG::VERBOSE << " new data for";
145 for (const Gaudi::Algorithm *parent_alg : dyn_data_consumer.second) {
146 out << " " << parent_alg->name();
147 }
148 out << " i:" << tmp_new_input_handles.size()
149 << " o:" << tmp_new_output_handles.size()
150 << endmsg;
151 }
152 updated |= ret;
153 if (ret) {
154 if (msgLvl(out,MSG::DEBUG)) {
155 if (Gaudi::Algorithm * const an_alg = dynamic_cast<Gaudi::Algorithm * const>(dyn_data_consumer.first); an_alg) {
156 out << MSG::DEBUG << an_alg->name() << " updated its data needs." << endmsg;
157 // DEBUG:
158 out << MSG::DEBUG << an_alg->name() << " inputs:";
159 for (const Gaudi::DataHandle *handle : an_alg->inputHandles()) {
160 out << " " << handle->fullKey();
161 }
162 out << endmsg;
163 }
164 else if (AlgTool *alg_tool = dynamic_cast<AlgTool * const>(dyn_data_consumer.first); alg_tool) {
165 out << MSG::DEBUG << alg_tool->name() << " updated its data needs." << endmsg;
166 // DEBUG:
167 out << MSG::DEBUG << alg_tool->name() << " inputs:";
168 for (const Gaudi::DataHandle *handle : alg_tool->inputHandles()) {
169 out << " " << handle->fullKey();
170 }
171 out << endmsg;
172 }
173 else {
174 out << MSG::WARNING << "Unknown dynamic data consumer type " << typeid(dyn_data_consumer.first).name() << endmsg;
175 }
176 }
177 }
178 for (Gaudi::Algorithm *parent_alg : dyn_data_consumer.second) {
179 input_data_out.reserve(input_data_out.size()+tmp_new_input_handles.size());
180 for (Gaudi::DataHandle *a_handle : tmp_new_input_handles) {
181 parent_alg->addDependency(a_handle->fullKey(), Gaudi::DataHandle::Reader);
182 input_data_out.push_back(&(a_handle->fullKey()));
183 if (msgLvl(out,MSG::DEBUG)) out << MSG::DEBUG << " addDependency new input for " << parent_alg->name() << " "
184 << a_handle->fullKey().className() << " / " << a_handle->objKey() << endmsg;
185 }
186 output_data_out.reserve(output_data_out.size()+tmp_new_output_handles.size());
187 for (Gaudi::DataHandle *a_handle : tmp_new_output_handles) {
188 parent_alg->addDependency(a_handle->fullKey(), Gaudi::DataHandle::Writer);
189 output_data_out.push_back(&(a_handle->fullKey()));
190 if (msgLvl(out,MSG::DEBUG)) out << MSG::DEBUG << " addDependency new output for " << parent_alg->name() << " "
191 << a_handle->fullKey().className() << " / " << a_handle->objKey() << endmsg;
192 }
193 }
194 }
195 return updated;
196 }
197}
#define endmsg
uint32_t CLID
The Class ID type.
Define macros for attributes used to control the static checker.
#define ATLAS_THREAD_SAFE
StatusCode addExtraDependencies(IClassIDSvc &clid_svc, std::vector< std::string > &undeclared_output_data, MsgStream &out)
Add extra output data which is not declared by any of the gathered components.
void gatherDataHandlesAndDynamicConsumers(const std::string &parent_name, Gaudi::Algorithm *theAlgorithm)
Gather the input and output data declared by the given algorithm, its child algorithms and their tool...
void updateDataNeeds(unsigned int max_pass, MsgStream &out)
Update the data dependencies of all components which dynamically declare tehm.
std::vector< DataObjID > m_extraOutputIDs
DataObjIDPtrColl m_inputHandles
DataObjIDPtrColl m_outputHandles
std::unordered_map< IDynamicDataConsumer *, std::vector< Gaudi::Algorithm * > > m_dynDataConsumer
std::unordered_set< const DataObjID *, DataObjID_PtrHasher, DataObjID_PtrEqual > DataObjIDPtrColl