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;
75 std::unordered_set<T> intersect(std::unordered_set<T>
const& iLHS, std::unordered_set<T>
const& iRHS) {
76 std::unordered_set<T>
result;
77 if(iLHS.size() < iRHS.size()) {
78 result.reserve(iLHS.size());
79 for(
auto const&
l: iLHS) {
80 if(iRHS.find(
l) != iRHS.end()) {
86 result.reserve(iRHS.size());
87 for(
auto const&
r: iRHS) {
88 if(iLHS.find(
r) != iLHS.end()) {
95 struct cycle_detector :
public boost::dfs_visitor<> {
97 static const unsigned int kRootVertexIndex=0;
99 cycle_detector(EdgeToPathMap
const& iEdgeToPathMap,
100 std::vector<std::vector<unsigned int>>
const& iPathIndexToModuleIndexOrder,
101 std::vector<std::string>
const& iPathNames,
102 std::unordered_map<unsigned int,std::string>
const& iModuleIndexToNames):
103 m_edgeToPathMap(iEdgeToPathMap),
104 m_pathIndexToModuleIndexOrder(iPathIndexToModuleIndexOrder),
105 m_pathNames(iPathNames),
106 m_indexToNames(iModuleIndexToNames){}
108 bool compare(Edge
const& iLHS, Edge
const& iRHS)
const;
110 void tree_edge(Edge
const& iEdge, Graph
const& iGraph) {
111 auto const&
index =
get(boost::vertex_index, iGraph);
114 for(
auto it = m_stack.begin(); it != m_stack.end(); ++it) {
118 m_stack.erase(it, m_stack.end());
123 m_stack.push_back(iEdge);
126 void finish_vertex(
unsigned int iVertex, Graph
const& iGraph) {
127 if(not m_stack.empty()) {
128 auto const&
index =
get(boost::vertex_index, iGraph);
130 if (iVertex ==
index[
source(m_stack.back(),iGraph)]) {
137 void back_edge(Edge
const& iEdge, Graph
const& iGraph) {
139 auto const&
index =
get(boost::vertex_index, iGraph);
141 if(kRootVertexIndex !=
index[
source(m_stack.front(),iGraph)]) {
146 m_stack.push_back(iEdge);
148 auto pop_stack = [](std::vector<Edge>*
stack) {
stack->pop_back(); };
149 std::unique_ptr<std::vector<Edge>,decltype(pop_stack)> guard(&m_stack,pop_stack);
154 std::vector<Edge> tempStack;
156 tempStack= findMinimumCycle(m_stack,iGraph);
157 checkCycleForProblem(tempStack,iGraph);
158 for(
auto const& edge: tempStack) {
162 m_verticiesInFundamentalCycles.insert(in);
163 m_verticiesInFundamentalCycles.insert(out);
168 m_fundamentalCycles.emplace_back(
std::move(tempStack));
171 void forward_or_cross_edge(Edge iEdge, Graph
const& iGraph)
175 IndexMap
const&
index =
get(boost::vertex_index, iGraph);
177 if(kRootVertexIndex != index[
source(m_stack.front(),iGraph)]) {
182 const unsigned int out =index[
target(iEdge,iGraph)];
186 if(m_verticiesInFundamentalCycles.end() == m_verticiesInFundamentalCycles.find(out)) {
190 for(
auto const& cycle: m_fundamentalCycles) {
192 auto itStartMatch = cycle.end();
193 for(
auto it =cycle.begin(); it!= cycle.end(); ++it) {
194 unsigned int inCycle =index[
source(*it,iGraph)];
201 if(itStartMatch == cycle.end()) {
208 m_stack.push_back(iEdge);
209 auto pop_stack = [](std::vector<Edge>*
stack) {
stack->pop_back(); };
210 std::unique_ptr<std::vector<Edge>,decltype(pop_stack)> guard(&m_stack,pop_stack);
211 auto tempStack= findMinimumCycle(m_stack,iGraph);
215 std::set<unsigned int> verticiesInStack;
216 for(
auto const& edge: tempStack) {
217 verticiesInStack.insert(index[
source(edge,iGraph)]);
224 auto itLastMatch = cycle.end();
225 for(
auto it=itStartMatch; it != cycle.end(); ++it) {
226 unsigned int outCycle =index[
target(*it,iGraph)];
227 if(verticiesInStack.end() != verticiesInStack.find(outCycle)) {
232 if(itLastMatch==cycle.end()) {
234 tempStack.insert(tempStack.end(),itStartMatch,cycle.end());
235 for(
auto it=cycle.begin(); it != itStartMatch;++it) {
236 unsigned int outCycle =index[
target(*it,iGraph)];
237 if(verticiesInStack.end() != verticiesInStack.find(outCycle)) {
242 if( itLastMatch==cycle.end()) {
249 tempStack.insert(tempStack.end(),cycle.begin(),itStartMatch);
251 tempStack.insert(tempStack.end(),cycle.begin(),itLastMatch+1);
254 if( (itStartMatch == cycle.begin()) and (cycle.end() == (itLastMatch+1)) ) {
259 tempStack.insert(tempStack.end(),itStartMatch,itLastMatch+1);
262 tempStack= findMinimumCycle(tempStack,iGraph);
263 checkCycleForProblem(tempStack,iGraph);
268 std::string const& pathName(
unsigned int iIndex)
const {
269 return m_pathNames[iIndex];
273 auto itFound =m_indexToNames.find(iIndex);
274 assert(itFound != m_indexToNames.end());
275 return itFound->second;
279 throwOnError(std::vector<Edge>
const& iEdges,
281 Graph
const& iGraph)
const {
282 std::stringstream oStream;
283 oStream <<
"Module run order problem found: \n";
284 bool first_edge =
true;
285 for(
auto const& edge: iEdges) {
286 unsigned int in =iIndex[
source(edge,iGraph)];
287 unsigned int out =iIndex[
target(edge,iGraph)];
296 auto iFound = m_edgeToPathMap.find(
SimpleEdge(in,out));
297 bool pathDependencyOnly =
true;
298 for(
auto dependency : iFound->second) {
300 pathDependencyOnly =
false;
304 if (pathDependencyOnly) {
305 oStream <<
" after "<<
moduleName(out)<<
" [path "<<pathName(iFound->second[0])<<
"]";
310 oStream<<
"\n Running in the threaded framework would lead to indeterminate results." 311 "\n Please change order of modules in mentioned Path(s) to avoid inconsistent module ordering.";
314 << oStream.str() <<
"\n";
317 std::vector<Edge> findMinimumCycle(std::vector<Edge>
const& iCycleEdges,
318 Graph
const& iGraph)
const {
328 IndexMap
const& index =
get(boost::vertex_index, iGraph);
330 std::vector<Edge> reducedEdges;
331 reducedEdges.reserve(iCycleEdges.size());
332 reducedEdges.push_back(iCycleEdges.back());
333 unsigned int lastIn = index[
source(iCycleEdges.back(),iGraph)];
334 const unsigned int finalVertex = index[
target(iCycleEdges.back(),iGraph)];
335 for(
auto it = iCycleEdges.rbegin()+1; it != iCycleEdges.rend(); ++it) {
336 unsigned int in =index[
source(*it,iGraph)];
337 unsigned int out =index[
target(*it,iGraph)];
339 reducedEdges.push_back(*it);
341 if(in == finalVertex) {
351 void checkCycleForProblem(std::vector<Edge>
const& iCycleEdges,
352 Graph
const& iGraph) {
356 bool hasDataDependency =
false;
359 IndexMap
const& index =
get(boost::vertex_index, iGraph);
361 unsigned int lastIn =index[
source(iCycleEdges.back(),iGraph)];
362 unsigned int lastOut = index[
target(iCycleEdges.back(),iGraph)];
363 bool lastEdgeHasDataDepencency =
false;
365 std::unordered_set<unsigned int> lastPathsSeen;
370 std::unordered_multimap<unsigned int, unsigned int> pathToModulesWhichMustAppearLater;
371 bool moduleAppearedEarlierInPath =
false;
373 for(
auto dependency: m_edgeToPathMap.find(SimpleEdge(lastIn,lastOut))->second) {
375 lastPathsSeen.insert(dependency);
377 lastEdgeHasDataDepencency =
true;
381 bool minimumInitialPathsSet =
false;
382 std::unordered_set<unsigned int> initialPaths(lastPathsSeen);
383 std::unordered_set<unsigned int> sharedPaths;
384 for(
auto const& edge: iCycleEdges) {
385 unsigned int in =index[
source(edge,iGraph)];
386 unsigned int out =index[
target(edge,iGraph)];
388 auto iFound = m_edgeToPathMap.find(
SimpleEdge(in,out));
389 std::unordered_set<unsigned int> pathsOnEdge;
390 bool edgeHasDataDependency =
false;
391 for(
auto dependency : iFound->second) {
394 hasDataDependency =
true;
395 edgeHasDataDependency =
true;
397 pathsOnEdge.insert(dependency);
399 auto const& pathIndicies = m_pathIndexToModuleIndexOrder[dependency];
400 auto pathToCheckRange = pathToModulesWhichMustAppearLater.equal_range(dependency);
401 for(
auto it = pathToCheckRange.first; it != pathToCheckRange.second; ) {
402 auto moduleIDToCheck = it->second;
403 if(moduleIDToCheck == in
or moduleIDToCheck==out) {
406 pathToModulesWhichMustAppearLater.erase(toErase);
409 bool alreadyAdvanced =
false;
410 for(
auto index : pathIndicies) {
416 alreadyAdvanced =
true;
417 pathToModulesWhichMustAppearLater.erase(toErase);
420 if(index == moduleIDToCheck) {
425 if(not alreadyAdvanced) {
431 sharedPaths = intersect(pathsOnEdge,lastPathsSeen);
432 if(sharedPaths.empty() ) {
433 minimumInitialPathsSet =
true;
434 if((not edgeHasDataDependency) and (not lastEdgeHasDataDepencency) and (not lastPathsSeen.empty())) {
440 if(edgeHasDataDependency and not lastPathsSeen.empty()) {
443 bool atLeastOnePathFailed =
false;
444 std::vector<unsigned int> pathsToWatch;
445 pathsToWatch.reserve(lastPathsSeen.size());
446 for(
auto seenPath: lastPathsSeen) {
447 if(pathsOnEdge.end() == pathsOnEdge.find(seenPath)) {
450 bool foundOut =
false;
451 for(
auto index: m_pathIndexToModuleIndexOrder[seenPath]) {
454 pathsToWatch.push_back(seenPath);
456 if(index == lastOut) {
458 atLeastOnePathFailed =
true;
462 if(atLeastOnePathFailed) {
471 if(not atLeastOnePathFailed) {
472 moduleAppearedEarlierInPath =
true;
473 for(
auto p: pathsToWatch) {
474 pathToModulesWhichMustAppearLater.emplace(
p,out);
478 lastPathsSeen = pathsOnEdge;
480 lastPathsSeen = sharedPaths;
481 if (not minimumInitialPathsSet) {
482 initialPaths = sharedPaths;
486 lastEdgeHasDataDepencency =edgeHasDataDependency;
488 if(moduleAppearedEarlierInPath and not pathToModulesWhichMustAppearLater.empty()) {
491 if(not hasDataDependency) {
494 if( (not initialPaths.empty()) and intersect(initialPaths,sharedPaths).empty() ) {
500 throwOnError(iCycleEdges,index,iGraph);
505 EdgeToPathMap
const& m_edgeToPathMap;
506 std::vector<std::vector<unsigned int>>
const& m_pathIndexToModuleIndexOrder;
507 std::vector<std::string>
const& m_pathNames;
508 std::unordered_map<unsigned int,std::string> m_indexToNames;
509 std::unordered_map<unsigned int, std::vector<unsigned int>> m_pathToModuleIndex;
511 std::vector<Edge> m_stack;
512 std::vector<std::vector<Edge>> m_fundamentalCycles;
513 std::set<unsigned int> m_verticiesInFundamentalCycles;
521 std::vector<std::vector<unsigned int>>
const& iPathIndexToModuleIndexOrder,
522 std::vector<std::string>
const& iPathNames,
523 std::unordered_map<unsigned int, std::string>
const& iModuleIndexToNames) {
526 std::vector<SimpleEdge> outList;
527 outList.reserve(iEdgeToPathMap.size());
528 for(
auto const& edgeInfo: iEdgeToPathMap) {
529 outList.push_back(edgeInfo.first);
532 Graph
g(outList.begin(),outList.end(), iModuleIndexToNames.size());
534 cycle_detector
detector(iEdgeToPathMap,iPathIndexToModuleIndexOrder,iPathNames,iModuleIndexToNames);
535 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