3 #include "boost/graph/graph_traits.hpp" 4 #include "boost/graph/graph_utility.hpp" 6 #include "cetlib/HorizontalRule.h" 7 #include "cetlib/compiler_macros.h" 8 #include "range/v3/view.hpp" 30 std::string result{*cb};
31 for (
auto i = std::next(cb),
e =
cend(names); i !=
e; ++i) {
38 inline std::string
const&
45 std::pair<ModuleGraph, std::string>
50 auto const nmodules = modInfos.
size();
65 return std::make_pair(module_graph, err);
75 std::map<path_name_t, ModuleGraph*> path_graphs;
76 auto const source_index = modInfos.
vertex_index(
"input_source");
77 for (
auto const& path_name : trigger_paths | views::keys |
78 views::transform([](
auto const&
path_spec) {
81 auto& path_graph = module_graph.create_subgraph();
83 add_vertex(source_index, path_graph);
84 path_graphs[path_name] = &path_graph;
87 auto vertex_names =
get(boost::vertex_name_t{}, module_graph);
88 for (
auto const& [module_name, info] : modInfos) {
91 auto const index = modInfos.vertex_index(module_name);
92 for (
auto const& path : info.paths) {
93 add_vertex(index, *path_graphs.at(path));
95 vertex_names[index] = module_name;
103 auto edge_label =
get(boost::edge_name, graph);
105 auto const& modu = modInfos.
info(u);
106 for (
auto const& dep : modu.consumed_products) {
108 auto const edge = add_edge(u, v, graph);
109 edge_label[edge.first] =
"prod";
120 auto path_label =
get(boost::edge_name, graph);
121 for (
auto const& [
path_spec, modules] : trigger_paths) {
124 auto prev =
cbegin(modules);
125 auto curr = prev + 1;
126 auto const end =
cend(modules);
127 while (curr !=
end) {
129 auto const ci = modInfos.
vertex_index(module_label(*curr));
130 auto const edge = add_edge(ci,
pi, graph);
144 auto const source_index = modInfos.
vertex_index(
"input_source");
145 auto sync_label =
get(boost::edge_name, graph);
146 if (!trigger_paths.empty()) {
147 auto const tr_index = modInfos.
vertex_index(
"TriggerResults");
148 for (
auto const& [
path_spec, modules] : trigger_paths) {
149 if (modules.empty()) {
152 auto const front_index =
154 auto const back_index =
156 auto const edge1 = add_edge(front_index, source_index, graph);
158 auto const edge2 = add_edge(tr_index, back_index, graph);
159 sync_label[edge2.first] =
"sync";
161 for (
auto const&
module : end_path) {
163 auto const edge = add_edge(index, tr_index, graph);
164 sync_label[edge.first] =
"sync";
166 }
else if (!end_path.empty()) {
167 for (
auto const&
module : end_path) {
169 auto const edge = add_edge(index, source_index, graph);
170 sync_label[edge.first] =
"sync";
174 auto constexpr invalid = std::numeric_limits<std::size_t>::max();
177 for (
auto const& [
path_spec, modules] : trigger_paths) {
178 auto preceding_filter_index = invalid;
179 for (
auto const&
module : modules) {
181 auto const& info = modInfos.
info(index);
182 if (preceding_filter_index != invalid) {
183 auto const edge = add_edge(index, preceding_filter_index, graph);
186 if (info.module_type == ModuleType::filter) {
187 preceding_filter_index = index;
192 if (trigger_paths.empty()) {
198 auto const tr_index = modInfos.
vertex_index(
"TriggerResults");
199 for (
auto const&
module : end_path) {
201 auto const& info = modInfos.
info(index);
202 for (
auto const& path : info.select_events) {
203 auto const edge = add_edge(index, tr_index, graph);
204 sync_label[edge.first] =
"filter:" + path;
215 auto make_range = [](
auto const pr) {
return subrange{pr.first, pr.second}; };
217 std::map<Vertex, std::set<Vertex>> illegal_dependencies;
218 for (
auto const& path_graph : make_range(graph.children())) {
220 make_range(vertices(path_graph)) |
221 views::transform([&path_graph](
auto const local_vertex) {
222 return path_graph.local_to_global(local_vertex);
227 for (
auto const out_edge : make_range(out_edges(gv, graph))) {
228 auto const tv =
target(out_edge, graph);
229 if (path_graph.find_vertex(tv).second) {
232 illegal_dependencies[gv].insert(tv);
237 if (illegal_dependencies.empty()) {
241 std::ostringstream oss;
242 oss <<
"\nThe following represent cross-path data-dependency errors:\n" 243 << cet::HorizontalRule{60}(
'-') <<
'\n';
244 for (
auto const& [mod_index, target_indices] : illegal_dependencies) {
245 auto const& module_name = modInfos.
name(mod_index);
246 auto const& mod_paths = modInfos.
info(mod_index).paths;
247 oss <<
" Module " << module_name <<
" on path" 248 << (mod_paths.size() == 1ull ?
" " :
"s ")
249 << comma_separated_list(mod_paths) <<
" depends on\n";
250 for (
auto const& dep : target_indices) {
251 auto const& dep_name = modInfos.
name(dep);
252 auto const& on_paths = modInfos.
info(dep).paths;
253 oss <<
" Module " << dep_name <<
" on path" 254 << (on_paths.size() == 1ull ?
" " :
"s ")
255 << comma_separated_list(on_paths) <<
'\n';
258 oss <<
"\nSuch errors occur whenever a module on one path depends on the " 260 <<
"from another. Such dependencies can be subtle--for example, a " 262 <<
"uses an event.getManyByType call cannot be shared across paths if " 264 <<
"that precede it in the paths do not give consistent result. Please " 266 <<
"configuration, or email artists@fnal.gov for assistance.\n";
271 struct path_matches {
273 explicit path_matches(std::string
const& name) : path_name{name} {}
275 operator()(paths_to_modules_t::value_type
const& pr)
const 277 return pr.first.name == path_name;
281 struct module_matches {
282 std::string module_name;
283 explicit module_matches(std::string
const& name) : module_name{name} {}
287 return module_label(info) == module_name;
298 std::map<module_name_t, name_set_t> illegal_module_orderings;
299 for (
auto const&
module : modInfos) {
300 auto const& module_name =
module.first;
302 auto const& module_paths =
module.second.paths;
306 if (module_paths.empty()) {
312 auto const& first_path_for_module = *
cbegin(module_paths);
313 auto const& path_it = std::find_if(trigger_paths.cbegin(),
314 trigger_paths.cend(),
315 path_matches{first_path_for_module});
316 assert(path_it != trigger_paths.cend());
318 auto const end =
cend(path_it->second);
319 auto const module_position =
320 std::find_if(begin,
end, module_matches{module_name});
321 assert(module_position !=
end);
323 for (
auto const& dep :
module.second.consumed_products) {
324 if (dep.label ==
"input_source") {
327 auto const dep_position =
328 std::find_if(begin,
end, module_matches{dep.label});
329 assert(dep_position !=
end);
330 if (dep_position < module_position) {
333 illegal_module_orderings[module_name].insert(dep.label);
337 if (illegal_module_orderings.empty()) {
341 std::ostringstream oss;
342 oss <<
"\nThe following are module-ordering errors due to declared " 343 "data-product dependencies:\n";
344 for (
auto const& mod : illegal_module_orderings) {
345 auto const& module_name = mod.first;
346 auto const mod_index = modInfos.vertex_index(module_name);
347 auto const& module_paths = modInfos.info(mod_index).paths;
348 oss <<
" Module " << module_name <<
" on path" 349 << (module_paths.size() == 1ull ?
" " :
"s ")
350 << comma_separated_list(module_paths)
351 <<
" depends on either itself or modules that follow it:\n";
352 for (
auto const& dep_name : mod.second) {
353 auto const dep_index = modInfos.vertex_index(dep_name);
354 auto const& on_paths = modInfos.info(dep_index).paths;
355 oss <<
" Module " << dep_name <<
" on path" 356 << (on_paths.size() == 1ull ?
" " :
"s ")
357 << comma_separated_list(on_paths)
358 << (module_name == dep_name ?
" (self circularity)" :
"") <<
'\n';
367 class graph_printer :
public boost::dfs_visitor<> {
369 explicit graph_printer(
371 std::set<Vertex>& vertices,
372 std::map<
path_name_t, std::set<EdgePair>>& path_edges,
373 std::map<
path_name_t, std::set<EdgePair>>& filter_edges,
374 std::set<EdgePair>& trigger_path_edges,
375 std::map<EdgePair, unsigned>& product_edges)
377 , vertices_{vertices}
378 , path_edges_{path_edges}
379 , filter_edges_{filter_edges}
380 , trigger_path_edges_{trigger_path_edges}
381 , product_edges_{product_edges}
409 enum class arrow_style { path, sync, source,
filter, prod };
412 arrow_style_for(std::string
const& edge_name)
414 auto pos = edge_name.find(
"path:");
416 return arrow_style::path;
418 pos = edge_name.find(
"sync");
420 return arrow_style::sync;
422 pos = edge_name.find(
"source:");
424 return arrow_style::source;
426 pos = edge_name.find(
"filter:");
428 return arrow_style::filter;
430 if (edge_name ==
"prod") {
431 return arrow_style::prod;
435 "An occurred while printing the DOT file for this process.\n"}
436 <<
"The edge name '" << edge_name <<
"' is not recognized.";
442 auto const u = source(e, g);
443 auto const v =
target(e, g);
444 auto const vertex_pair = std::make_pair(u, v);
445 auto const& edge_name =
get(boost::edge_name, g,
e);
446 switch (arrow_style_for(edge_name)) {
447 case arrow_style::path: {
448 auto path_name = edge_name.substr(5);
449 path_edges_[path_name].insert(vertex_pair);
452 case arrow_style::sync: {
453 trigger_path_edges_.insert(vertex_pair);
456 case arrow_style::source: {
457 auto path_name = edge_name.substr(7);
458 path_edges_[path_name].insert(vertex_pair);
461 case arrow_style::filter: {
462 auto path_name = edge_name.substr(7);
463 filter_edges_[path_name].insert(vertex_pair);
466 case arrow_style::prod:
467 ++product_edges_[vertex_pair];
472 std::set<Vertex>& vertices_;
473 std::map<path_name_t, std::set<EdgePair>>& path_edges_;
474 std::map<path_name_t, std::set<EdgePair>>& filter_edges_;
475 std::set<EdgePair>& trigger_path_edges_;
476 std::map<EdgePair, unsigned>& product_edges_;
485 std::set<Vertex> vertices;
486 std::map<path_name_t, std::set<EdgePair>> path_edges;
487 std::map<path_name_t, std::set<EdgePair>> filter_edges;
488 std::set<EdgePair> trigger_path_edges;
489 std::map<EdgePair, unsigned> product_edges;
490 graph_printer printer{info_map,
496 boost::depth_first_search(graph, visitor(printer));
500 for (
auto const& v : vertices) {
501 auto const& name = info_map.
name(v);
502 auto const& info = info_map.
info(v);
503 if (name ==
"input_source") {
504 os <<
" \"input_source\"[shape=box label=source]";
505 }
else if (name ==
"TriggerResults") {
506 os <<
" \"" << name <<
'\"';
507 os <<
"[shape=box style=filled fillcolor=black label=\"\" height=0.1 " 510 os <<
" \"" << name <<
'\"';
512 os <<
"[style=filled fillcolor=pink]";
519 for (
auto const& [path_name, edges] : path_edges) {
521 os <<
" \"" << info_map.
name(
source) <<
"\" -> \"" 522 << info_map.
name(
target) <<
'\"' <<
"[label=\"" << path_name
523 <<
"\" color=gray];\n";
528 for (
auto const& [path_name, edges] : filter_edges) {
530 os <<
" \"" << info_map.
name(
source) <<
"\" -> \"" 531 << info_map.
name(
target) <<
'\"' <<
"[label=\"" << path_name
532 <<
"\" color=red];\n";
537 for (
auto const& [
source,
target] : trigger_path_edges) {
539 <<
'\"' <<
"[style=invisible arrowhead=none];\n";
543 for (
auto const& [edge_pair, multiplicity] : product_edges) {
547 if (multiplicity > 1) {
548 os <<
"[label=\"" << multiplicity <<
"\" color=black]";
decltype(auto) constexpr cend(T &&obj)
ADL-aware version of std::cend.
boost::graph_traits< ModuleGraph >::edge_descriptor Edge
ModuleType module_type(std::string const &full_key)
std::string verify_in_order_dependencies(ModuleGraphInfoMap const &modules, paths_to_modules_t const &trigger_paths)
decltype(auto) constexpr end(T &&obj)
ADL-aware version of std::end.
std::set< std::string > name_set_t
std::vector< WorkerInPath::ConfigInfo > configs_t
cet::exempt_ptr< detail::ModuleConfigInfo const > moduleConfigInfo
void print_module_graph(std::ostream &os, ModuleGraphInfoMap const &modInfos, ModuleGraph const &graph)
std::vector< std::pair< PathSpec, configs_t >> paths_to_modules_t
auto vertex_index(module_name_t const &name) const -> distance_t
bool is_modifier(ModuleType const mt)
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
auto const & info(std::size_t const i) const
void make_synchronization_edges(ModuleGraphInfoMap const &modInfos, paths_to_modules_t const &trigger_paths, configs_t const &end_path, ModuleGraph &graph)
void make_trigger_path_subgraphs(ModuleGraphInfoMap const &modInfos, paths_to_modules_t const &trigger_paths, ModuleGraph &graph)
std::pair< Vertex, Vertex > EdgePair
auto const & name(std::size_t const i) const
constexpr T pi()
Returns the constant pi (up to 35 decimal digits of precision)
cout<< "-> Edep in the target
decltype(auto) constexpr cbegin(T &&obj)
ADL-aware version of std::cbegin.
PathSpec path_spec(std::string const &path_spec)
boost::subgraph< Graph > ModuleGraph
boost::graph_traits< ModuleGraph >::vertex_descriptor Vertex
decltype(auto) constexpr begin(T &&obj)
ADL-aware version of std::begin.
std::string verify_no_interpath_dependencies(ModuleGraphInfoMap const &modInfos, ModuleGraph const &graph)
std::string module_name_t
void make_path_ordering_edges(ModuleGraphInfoMap const &modInfos, paths_to_modules_t const &paths, ModuleGraph &graph)
std::pair< ModuleGraph, std::string > make_module_graph(ModuleGraphInfoMap const &modInfos, paths_to_modules_t const &trigger_paths, configs_t const &end_path)
void make_product_dependency_edges(ModuleGraphInfoMap const &modInfos, ModuleGraph &graph)