20 #include "boost/graph/graph_traits.hpp" 21 #include "boost/graph/adjacency_list.hpp" 22 #include "boost/graph/depth_first_search.hpp" 23 #include "boost/graph/visitors.hpp" 67 typedef std::pair<unsigned int, unsigned int>
SimpleEdge;
68 typedef std::map<SimpleEdge, std::vector<unsigned int>>
EdgeToPathMap;
70 typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS> Graph;
72 typedef boost::graph_traits<Graph>::edge_descriptor Edge;
73 struct cycle_detector :
public boost::dfs_visitor<> {
75 static const unsigned int kRootVertexIndex=0;
77 cycle_detector(EdgeToPathMap
const& iEdgeToPathMap,
78 std::vector<std::vector<unsigned int>>
const& iPathIndexToModuleIndexOrder,
79 std::vector<std::string>
const& iPathNames,
80 std::unordered_map<unsigned int,std::string>
const& iModuleIndexToNames):
81 m_edgeToPathMap(iEdgeToPathMap),
82 m_pathIndexToModuleIndexOrder(iPathIndexToModuleIndexOrder),
83 m_pathNames(iPathNames),
84 m_indexToNames(iModuleIndexToNames){}
86 bool compare(Edge
const& iLHS, Edge
const& iRHS)
const;
88 void tree_edge(Edge
const& iEdge, Graph
const& iGraph) {
89 auto const&
index =
get(boost::vertex_index, iGraph);
92 for(
auto it = m_stack.begin(); it != m_stack.end(); ++it) {
96 m_stack.erase(it, m_stack.end());
101 m_stack.push_back(iEdge);
104 void finish_vertex(
unsigned int iVertex, Graph
const& iGraph) {
105 if(not m_stack.empty()) {
106 auto const&
index =
get(boost::vertex_index, iGraph);
108 if (iVertex ==
index[
source(m_stack.back(),iGraph)]) {
115 void back_edge(Edge
const& iEdge, Graph
const& iGraph) {
117 auto const&
index =
get(boost::vertex_index, iGraph);
119 if(kRootVertexIndex !=
index[
source(m_stack.front(),iGraph)]) {
124 m_stack.push_back(iEdge);
126 auto pop_stack = [](std::vector<Edge>*
stack) {
stack->pop_back(); };
127 std::unique_ptr<std::vector<Edge>,decltype(pop_stack)> guard(&m_stack,pop_stack);
132 std::vector<Edge> tempStack;
134 tempStack= findMinimumCycle(m_stack,iGraph);
135 checkCycleForProblem(tempStack,iGraph);
136 for(
auto const& edge: tempStack) {
140 m_verticiesInFundamentalCycles.insert(in);
141 m_verticiesInFundamentalCycles.insert(out);
146 m_fundamentalCycles.emplace_back(
std::move(tempStack));
149 void forward_or_cross_edge(Edge iEdge, Graph
const& iGraph)
153 IndexMap
const&
index =
get(boost::vertex_index, iGraph);
155 if(kRootVertexIndex != index[
source(m_stack.front(),iGraph)]) {
160 const unsigned int out =index[
target(iEdge,iGraph)];
164 if(m_verticiesInFundamentalCycles.end() == m_verticiesInFundamentalCycles.find(out)) {
168 for(
auto const& cycle: m_fundamentalCycles) {
170 auto itStartMatch = cycle.end();
171 for(
auto it =cycle.begin(); it!= cycle.end(); ++it) {
172 unsigned int inCycle =index[
source(*it,iGraph)];
179 if(itStartMatch == cycle.end()) {
186 m_stack.push_back(iEdge);
187 auto pop_stack = [](std::vector<Edge>*
stack) {
stack->pop_back(); };
188 std::unique_ptr<std::vector<Edge>,decltype(pop_stack)> guard(&m_stack,pop_stack);
189 auto tempStack= findMinimumCycle(m_stack,iGraph);
193 std::set<unsigned int> verticiesInStack;
194 for(
auto const& edge: tempStack) {
195 verticiesInStack.insert(index[
source(edge,iGraph)]);
202 auto itLastMatch = cycle.end();
203 for(
auto it=itStartMatch; it != cycle.end(); ++it) {
204 unsigned int outCycle =index[
target(*it,iGraph)];
205 if(verticiesInStack.end() != verticiesInStack.find(outCycle)) {
210 if(itLastMatch==cycle.end()) {
212 tempStack.insert(tempStack.end(),itStartMatch,cycle.end());
213 for(
auto it=cycle.begin(); it != itStartMatch;++it) {
214 unsigned int outCycle =index[
target(*it,iGraph)];
215 if(verticiesInStack.end() != verticiesInStack.find(outCycle)) {
220 if( itLastMatch==cycle.end()) {
227 tempStack.insert(tempStack.end(),cycle.begin(),itStartMatch);
229 tempStack.insert(tempStack.end(),cycle.begin(),itLastMatch+1);
232 if( (itStartMatch == cycle.begin()) and (cycle.end() == (itLastMatch+1)) ) {
237 tempStack.insert(tempStack.end(),itStartMatch,itLastMatch+1);
240 tempStack= findMinimumCycle(tempStack,iGraph);
241 checkCycleForProblem(tempStack,iGraph);
246 std::string const& pathName(
unsigned int iIndex)
const {
247 return m_pathNames[iIndex];
251 auto itFound =m_indexToNames.find(iIndex);
252 assert(itFound != m_indexToNames.end());
253 return itFound->second;
257 throwOnError(std::vector<Edge>
const& iEdges,
259 Graph
const& iGraph)
const {
260 std::stringstream oStream;
261 oStream <<
"Module run order problem found: \n";
262 bool first_edge =
true;
263 for(
auto const& edge: iEdges) {
264 unsigned int in =iIndex[
source(edge,iGraph)];
265 unsigned int out =iIndex[
target(edge,iGraph)];
274 auto iFound = m_edgeToPathMap.find(
SimpleEdge(in,out));
275 bool pathDependencyOnly =
true;
276 for(
auto dependency : iFound->second) {
278 pathDependencyOnly =
false;
282 if (pathDependencyOnly) {
283 oStream <<
" after "<<
moduleName(out)<<
" [path "<<pathName(iFound->second[0])<<
"]";
288 oStream<<
"\n Running in the threaded framework would lead to indeterminate results." 289 "\n Please change order of modules in mentioned Path(s) to avoid inconsistent module ordering.";
292 << oStream.str() <<
"\n";
295 std::vector<Edge> findMinimumCycle(std::vector<Edge>
const& iCycleEdges,
296 Graph
const& iGraph)
const {
306 IndexMap
const& index =
get(boost::vertex_index, iGraph);
308 std::vector<Edge> reducedEdges;
309 reducedEdges.reserve(iCycleEdges.size());
310 reducedEdges.push_back(iCycleEdges.back());
311 unsigned int lastIn = index[
source(iCycleEdges.back(),iGraph)];
312 const unsigned int finalVertex = index[
target(iCycleEdges.back(),iGraph)];
313 for(
auto it = iCycleEdges.rbegin()+1; it != iCycleEdges.rend(); ++it) {
314 unsigned int in =index[
source(*it,iGraph)];
315 unsigned int out =index[
target(*it,iGraph)];
317 reducedEdges.push_back(*it);
319 if(in == finalVertex) {
329 void checkCycleForProblem(std::vector<Edge>
const& iCycleEdges,
330 Graph
const& iGraph) {
334 bool hasDataDependency =
false;
337 IndexMap
const& index =
get(boost::vertex_index, iGraph);
339 unsigned int lastIn =index[
source(iCycleEdges.back(),iGraph)];
340 unsigned int lastOut = index[
target(iCycleEdges.back(),iGraph)];
341 bool lastEdgeHasDataDepencency =
false;
343 std::unordered_set<unsigned int> lastPathsSeen;
348 std::unordered_multimap<unsigned int, unsigned int> pathToModulesWhichMustAppearLater;
349 bool moduleAppearedEarlierInPath =
false;
351 for(
auto dependency: m_edgeToPathMap.find(SimpleEdge(lastIn,lastOut))->second) {
353 lastPathsSeen.insert(dependency);
355 lastEdgeHasDataDepencency =
true;
358 for(
auto const& edge: iCycleEdges) {
359 unsigned int in =index[
source(edge,iGraph)];
360 unsigned int out =index[
target(edge,iGraph)];
362 auto iFound = m_edgeToPathMap.find(
SimpleEdge(in,out));
363 std::unordered_set<unsigned int> pathsOnEdge;
364 bool edgeHasDataDependency =
false;
365 for(
auto dependency : iFound->second) {
368 hasDataDependency =
true;
369 edgeHasDataDependency =
true;
371 pathsOnEdge.insert(dependency);
373 auto const& pathIndicies = m_pathIndexToModuleIndexOrder[dependency];
374 auto pathToCheckRange = pathToModulesWhichMustAppearLater.equal_range(dependency);
375 for(
auto it = pathToCheckRange.first; it != pathToCheckRange.second; ) {
376 auto moduleIDToCheck = it->second;
377 if(moduleIDToCheck == in
or moduleIDToCheck==out) {
380 pathToModulesWhichMustAppearLater.erase(toErase);
383 bool alreadyAdvanced =
false;
384 for(
auto index : pathIndicies) {
390 alreadyAdvanced =
true;
391 pathToModulesWhichMustAppearLater.erase(toErase);
394 if(index == moduleIDToCheck) {
399 if(not alreadyAdvanced) {
405 if((pathsOnEdge != lastPathsSeen) ) {
406 if((not edgeHasDataDependency) and (not lastEdgeHasDataDepencency) and (not lastPathsSeen.empty())) {
412 if(edgeHasDataDependency and not lastPathsSeen.empty()) {
415 bool atLeastOnePathFailed =
false;
416 std::vector<unsigned int> pathsToWatch;
417 pathsToWatch.reserve(lastPathsSeen.size());
418 for(
auto seenPath: lastPathsSeen) {
419 if(pathsOnEdge.end() == pathsOnEdge.find(seenPath)) {
422 bool foundOut =
false;
423 for(
auto index: m_pathIndexToModuleIndexOrder[seenPath]) {
426 pathsToWatch.push_back(seenPath);
428 if(index == lastOut) {
430 atLeastOnePathFailed =
true;
434 if(atLeastOnePathFailed) {
443 if(not atLeastOnePathFailed) {
444 moduleAppearedEarlierInPath =
true;
445 for(
auto p: pathsToWatch) {
446 pathToModulesWhichMustAppearLater.emplace(
p,out);
450 lastPathsSeen = pathsOnEdge;
452 lastEdgeHasDataDepencency =edgeHasDataDependency;
455 if(moduleAppearedEarlierInPath and not pathToModulesWhichMustAppearLater.empty()) {
458 if(not hasDataDependency) {
461 throwOnError(iCycleEdges,index,iGraph);
466 EdgeToPathMap
const& m_edgeToPathMap;
467 std::vector<std::vector<unsigned int>>
const& m_pathIndexToModuleIndexOrder;
468 std::vector<std::string>
const& m_pathNames;
469 std::unordered_map<unsigned int,std::string> m_indexToNames;
470 std::unordered_map<unsigned int, std::vector<unsigned int>> m_pathToModuleIndex;
472 std::vector<Edge> m_stack;
473 std::vector<std::vector<Edge>> m_fundamentalCycles;
474 std::set<unsigned int> m_verticiesInFundamentalCycles;
482 std::vector<std::vector<unsigned int>>
const& iPathIndexToModuleIndexOrder,
483 std::vector<std::string>
const& iPathNames,
484 std::unordered_map<unsigned int, std::string>
const& iModuleIndexToNames) {
487 std::vector<SimpleEdge> outList;
488 outList.reserve(iEdgeToPathMap.size());
489 for(
auto const& edgeInfo: iEdgeToPathMap) {
490 outList.push_back(edgeInfo.first);
493 Graph
g(outList.begin(),outList.end(), iModuleIndexToNames.size());
495 cycle_detector
detector(iEdgeToPathMap,iPathIndexToModuleIndexOrder,iPathNames,iModuleIndexToNames);
496 boost::depth_first_search(
g,boost::visitor(detector));
bool compare(const P &i, const P &j)
void throwIfImproperDependencies(EdgeToPathMap const &, std::vector< std::vector< unsigned int >> const &iPathIndexToModuleIndexOrder, std::vector< std::string > const &iPathNames, std::unordered_map< unsigned int, std::string > const &iModuleIndexToNames)
std::map< SimpleEdge, std::vector< unsigned int >> EdgeToPathMap
constexpr auto kDataDependencyIndex
The Signals That Services Can Subscribe To This is based on ActivityRegistry and is current per Services can connect to the signals distributed by the ActivityRegistry in order to monitor the activity of the application Each possible callback has some defined which we here list in angle e g
std::string moduleName(Provenance const &provenance)
The Signals That Services Can Subscribe To This is based on ActivityRegistry and is current per Services can connect to the signals distributed by the ActivityRegistry in order to monitor the activity of the application Each possible callback has some defined which we here list in angle e< void, edm::EventID const &, edm::Timestamp const & > We also list in braces which AR_WATCH_USING_METHOD_ is used for those or
static std::string const source
std::pair< unsigned int, unsigned int > SimpleEdge