19 #include "boost/graph/graph_traits.hpp" 20 #include "boost/graph/adjacency_list.hpp" 21 #include "boost/graph/depth_first_search.hpp" 22 #include "boost/graph/visitors.hpp" 66 typedef std::pair<unsigned int, unsigned int>
SimpleEdge;
67 typedef std::map<SimpleEdge, std::vector<unsigned int>>
EdgeToPathMap;
69 typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS>
Graph;
71 typedef boost::graph_traits<Graph>::edge_descriptor Edge;
74 std::unordered_set<T> intersect(std::unordered_set<T>
const& iLHS, std::unordered_set<T>
const& iRHS) {
75 std::unordered_set<T>
result;
76 if (iLHS.size() < iRHS.size()) {
77 result.reserve(iLHS.size());
78 for (
auto const&
l : iLHS) {
79 if (iRHS.find(
l) != iRHS.end()) {
85 result.reserve(iRHS.size());
86 for (
auto const&
r : iRHS) {
87 if (iLHS.find(
r) != iLHS.end()) {
94 struct cycle_detector :
public boost::dfs_visitor<> {
95 static const unsigned int kRootVertexIndex = 0;
97 cycle_detector(EdgeToPathMap
const& iEdgeToPathMap,
98 std::vector<std::vector<unsigned int>>
const& iPathIndexToModuleIndexOrder,
99 std::vector<std::string>
const& iPathNames,
100 std::unordered_map<unsigned int, std::string>
const& iModuleIndexToNames)
101 : m_edgeToPathMap(iEdgeToPathMap),
102 m_pathIndexToModuleIndexOrder(iPathIndexToModuleIndexOrder),
103 m_pathNames(iPathNames),
104 m_indexToNames(iModuleIndexToNames) {}
106 bool compare(Edge
const& iLHS, Edge
const& iRHS)
const;
108 void tree_edge(Edge
const& iEdge, Graph
const& iGraph) {
109 auto const&
index =
get(boost::vertex_index, iGraph);
112 for (
auto it = m_stack.begin(); it != m_stack.end(); ++it) {
116 m_stack.erase(it, m_stack.end());
121 m_stack.push_back(iEdge);
124 void finish_vertex(
unsigned int iVertex, Graph
const& iGraph) {
125 if (not m_stack.empty()) {
126 auto const&
index =
get(boost::vertex_index, iGraph);
128 if (iVertex ==
index[
source(m_stack.back(), iGraph)]) {
135 void back_edge(Edge
const& iEdge, Graph
const& iGraph) {
136 auto const&
index =
get(boost::vertex_index, iGraph);
138 if (kRootVertexIndex !=
index[
source(m_stack.front(), iGraph)]) {
143 m_stack.push_back(iEdge);
145 auto pop_stack = [](std::vector<Edge>*
stack) {
stack->pop_back(); };
146 std::unique_ptr<std::vector<Edge>, decltype(pop_stack)> guard(&m_stack, pop_stack);
151 std::vector<Edge> tempStack;
153 tempStack = findMinimumCycle(m_stack, iGraph);
154 checkCycleForProblem(tempStack, iGraph);
155 for (
auto const& edge : tempStack) {
159 m_verticiesInFundamentalCycles.insert(in);
160 m_verticiesInFundamentalCycles.insert(out);
165 m_fundamentalCycles.emplace_back(
std::move(tempStack));
168 void forward_or_cross_edge(Edge iEdge, Graph
const& iGraph) {
170 IndexMap
const&
index =
get(boost::vertex_index, iGraph);
172 if (kRootVertexIndex != index[
source(m_stack.front(), iGraph)]) {
177 const unsigned int out = index[
target(iEdge, iGraph)];
181 if (m_verticiesInFundamentalCycles.end() == m_verticiesInFundamentalCycles.find(out)) {
185 for (
auto const& cycle : m_fundamentalCycles) {
187 auto itStartMatch = cycle.end();
188 for (
auto it = cycle.begin(); it != cycle.end(); ++it) {
189 unsigned int inCycle = index[
source(*it, iGraph)];
191 if (out == inCycle) {
196 if (itStartMatch == cycle.end()) {
203 m_stack.push_back(iEdge);
204 auto pop_stack = [](std::vector<Edge>*
stack) {
stack->pop_back(); };
205 std::unique_ptr<std::vector<Edge>, decltype(pop_stack)> guard(&m_stack, pop_stack);
206 auto tempStack = findMinimumCycle(m_stack, iGraph);
210 std::set<unsigned int> verticiesInStack;
211 for (
auto const& edge : tempStack) {
212 verticiesInStack.insert(index[
source(edge, iGraph)]);
217 auto itLastMatch = cycle.end();
218 for (
auto it = itStartMatch; it != cycle.end(); ++it) {
219 unsigned int outCycle = index[
target(*it, iGraph)];
220 if (verticiesInStack.end() != verticiesInStack.find(outCycle)) {
225 if (itLastMatch == cycle.end()) {
227 tempStack.insert(tempStack.end(), itStartMatch, cycle.end());
228 for (
auto it = cycle.begin(); it != itStartMatch; ++it) {
229 unsigned int outCycle = index[
target(*it, iGraph)];
230 if (verticiesInStack.end() != verticiesInStack.find(outCycle)) {
235 if (itLastMatch == cycle.end()) {
242 tempStack.insert(tempStack.end(), cycle.begin(), itStartMatch);
244 tempStack.insert(tempStack.end(), cycle.begin(), itLastMatch + 1);
247 if ((itStartMatch == cycle.begin()) and (cycle.end() == (itLastMatch + 1))) {
252 tempStack.insert(tempStack.end(), itStartMatch, itLastMatch + 1);
255 tempStack = findMinimumCycle(tempStack, iGraph);
256 checkCycleForProblem(tempStack, iGraph);
261 std::string const& pathName(
unsigned int iIndex)
const {
return m_pathNames[iIndex]; }
264 auto itFound = m_indexToNames.find(iIndex);
265 assert(itFound != m_indexToNames.end());
266 return itFound->second;
269 void throwOnError(std::vector<Edge>
const& iEdges,
271 Graph
const& iGraph)
const {
272 std::stringstream oStream;
273 oStream <<
"Module run order problem found: \n";
274 bool first_edge =
true;
275 for (
auto const& edge : iEdges) {
276 unsigned int in = iIndex[
source(edge, iGraph)];
277 unsigned int out = iIndex[
target(edge, iGraph)];
286 auto iFound = m_edgeToPathMap.find(
SimpleEdge(in, out));
287 bool pathDependencyOnly =
true;
288 for (
auto dependency : iFound->second) {
290 pathDependencyOnly =
false;
294 if (pathDependencyOnly) {
295 oStream <<
" after " <<
moduleName(out) <<
" [path " << pathName(iFound->second[0]) <<
"]";
300 oStream <<
"\n Running in the threaded framework would lead to indeterminate results." 301 "\n Please change order of modules in mentioned Path(s) to avoid inconsistent module ordering.";
306 std::vector<Edge> findMinimumCycle(std::vector<Edge>
const& iCycleEdges, Graph
const& iGraph)
const {
316 IndexMap
const& index =
get(boost::vertex_index, iGraph);
318 std::vector<Edge> reducedEdges;
319 reducedEdges.reserve(iCycleEdges.size());
320 reducedEdges.push_back(iCycleEdges.back());
321 unsigned int lastIn = index[
source(iCycleEdges.back(), iGraph)];
322 const unsigned int finalVertex = index[
target(iCycleEdges.back(), iGraph)];
323 for (
auto it = iCycleEdges.rbegin() + 1; it != iCycleEdges.rend(); ++it) {
324 unsigned int in = index[
source(*it, iGraph)];
325 unsigned int out = index[
target(*it, iGraph)];
327 reducedEdges.push_back(*it);
329 if (in == finalVertex) {
339 void checkCycleForProblem(std::vector<Edge>
const& iCycleEdges, Graph
const& iGraph) {
343 bool hasDataDependency =
false;
346 IndexMap
const& index =
get(boost::vertex_index, iGraph);
348 unsigned int lastIn = index[
source(iCycleEdges.back(), iGraph)];
349 unsigned int lastOut = index[
target(iCycleEdges.back(), iGraph)];
350 bool lastEdgeHasDataDepencency =
false;
352 std::unordered_set<unsigned int> lastPathsSeen;
357 std::unordered_multimap<unsigned int, unsigned int> pathToModulesWhichMustAppearLater;
358 bool moduleAppearedEarlierInPath =
false;
360 for (
auto dependency : m_edgeToPathMap.find(SimpleEdge(lastIn, lastOut))->second) {
362 lastPathsSeen.insert(dependency);
364 lastEdgeHasDataDepencency =
true;
368 bool minimumInitialPathsSet =
false;
369 std::unordered_set<unsigned int> initialPaths(lastPathsSeen);
370 std::unordered_set<unsigned int> sharedPaths;
371 for (
auto const& edge : iCycleEdges) {
372 unsigned int in = index[
source(edge, iGraph)];
373 unsigned int out = index[
target(edge, iGraph)];
375 auto iFound = m_edgeToPathMap.find(
SimpleEdge(in, out));
376 std::unordered_set<unsigned int> pathsOnEdge;
377 bool edgeHasDataDependency =
false;
378 for (
auto dependency : iFound->second) {
381 hasDataDependency =
true;
382 edgeHasDataDependency =
true;
384 pathsOnEdge.insert(dependency);
386 auto const& pathIndicies = m_pathIndexToModuleIndexOrder[dependency];
387 auto pathToCheckRange = pathToModulesWhichMustAppearLater.equal_range(dependency);
388 for (
auto it = pathToCheckRange.first; it != pathToCheckRange.second;) {
389 auto moduleIDToCheck = it->second;
390 if (moduleIDToCheck == in
or moduleIDToCheck == out) {
393 pathToModulesWhichMustAppearLater.erase(toErase);
396 bool alreadyAdvanced =
false;
397 for (
auto index : pathIndicies) {
403 alreadyAdvanced =
true;
404 pathToModulesWhichMustAppearLater.erase(toErase);
407 if (index == moduleIDToCheck) {
412 if (not alreadyAdvanced) {
418 sharedPaths = intersect(pathsOnEdge, lastPathsSeen);
419 if (sharedPaths.empty()) {
420 minimumInitialPathsSet =
true;
421 if ((not edgeHasDataDependency) and (not lastEdgeHasDataDepencency) and (not lastPathsSeen.empty())) {
427 if (edgeHasDataDependency and not lastPathsSeen.empty()) {
430 bool atLeastOnePathFailed =
false;
431 std::vector<unsigned int> pathsToWatch;
432 pathsToWatch.reserve(lastPathsSeen.size());
433 for (
auto seenPath : lastPathsSeen) {
434 if (pathsOnEdge.end() == pathsOnEdge.find(seenPath)) {
437 bool foundOut =
false;
438 for (
auto index : m_pathIndexToModuleIndexOrder[seenPath]) {
441 pathsToWatch.push_back(seenPath);
443 if (index == lastOut) {
445 atLeastOnePathFailed =
true;
449 if (atLeastOnePathFailed) {
458 if (not atLeastOnePathFailed) {
459 moduleAppearedEarlierInPath =
true;
460 for (
auto p : pathsToWatch) {
461 pathToModulesWhichMustAppearLater.emplace(
p, out);
465 lastPathsSeen = pathsOnEdge;
467 lastPathsSeen = sharedPaths;
468 if (not minimumInitialPathsSet) {
469 initialPaths = sharedPaths;
473 lastEdgeHasDataDepencency = edgeHasDataDependency;
475 if (moduleAppearedEarlierInPath and not pathToModulesWhichMustAppearLater.empty()) {
478 if (not hasDataDependency) {
481 if ((not initialPaths.empty()) and intersect(initialPaths, sharedPaths).empty()) {
487 throwOnError(iCycleEdges, index, iGraph);
490 EdgeToPathMap
const& m_edgeToPathMap;
491 std::vector<std::vector<unsigned int>>
const& m_pathIndexToModuleIndexOrder;
492 std::vector<std::string>
const& m_pathNames;
493 std::unordered_map<unsigned int, std::string> m_indexToNames;
494 std::unordered_map<unsigned int, std::vector<unsigned int>> m_pathToModuleIndex;
496 std::vector<Edge> m_stack;
497 std::vector<std::vector<Edge>> m_fundamentalCycles;
498 std::set<unsigned int> m_verticiesInFundamentalCycles;
503 std::vector<std::vector<unsigned int>>
const& iPathIndexToModuleIndexOrder,
504 std::vector<std::string>
const& iPathNames,
505 std::unordered_map<unsigned int, std::string>
const& iModuleIndexToNames) {
507 std::vector<SimpleEdge> outList;
508 outList.reserve(iEdgeToPathMap.size());
509 for (
auto const& edgeInfo : iEdgeToPathMap) {
510 outList.push_back(edgeInfo.first);
513 Graph
g(outList.begin(), outList.end(), iModuleIndexToNames.size());
515 cycle_detector
detector(iEdgeToPathMap, iPathIndexToModuleIndexOrder, iPathNames, iModuleIndexToNames);
516 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
DDCompactView::Graph Graph
std::pair< unsigned int, unsigned int > SimpleEdge