@@ -85,9 +85,42 @@ void format_requirements(std::string& label, const reduction_list& reductions, c
8585 }
8686}
8787
88+ template <typename IdType>
89+ void print_dependencies (
90+ const std::vector<dependency_record<IdType>>& dependencies, std::string& dot,
91+ const std::function<std::string(IdType)> id_transform = [](IdType id) { return std::to_string (id); }) {
92+ // Sort and deduplicate edges
93+ struct dependency_edge {
94+ IdType predecessor;
95+ IdType successor;
96+ };
97+ struct dependency_edge_order {
98+ bool operator ()(const dependency_edge& lhs, const dependency_edge& rhs) const {
99+ if (lhs.predecessor < rhs.predecessor ) return true ;
100+ if (lhs.predecessor > rhs.predecessor ) return false ;
101+ return lhs.successor < rhs.successor ;
102+ }
103+ };
104+ struct dependency_kind_order {
105+ bool operator ()(const std::pair<dependency_kind, dependency_origin>& lhs, const std::pair<dependency_kind, dependency_origin>& rhs) const {
106+ return (lhs.first == dependency_kind::true_dep && rhs.first != dependency_kind::true_dep);
107+ }
108+ };
109+ std::map<dependency_edge, std::set<std::pair<dependency_kind, dependency_origin>, dependency_kind_order>, dependency_edge_order>
110+ dependencies_by_edge; // ordered and unique
111+ for (const auto & dep : dependencies) {
112+ dependencies_by_edge[{dep.predecessor , dep.successor }].insert (std::pair{dep.kind , dep.origin });
113+ }
114+ for (const auto & [edge, meta] : dependencies_by_edge) {
115+ // If there's at most two edges, take the first one (likely a true dependency followed by an anti-dependency). If there's more, bail (don't style).
116+ const auto style = meta.size () <= 2 ? dependency_style (meta.begin ()->first , meta.begin ()->second ) : std::string{};
117+ fmt::format_to (std::back_inserter (dot), " {}->{}[{}];" , id_transform (edge.predecessor ), id_transform (edge.successor ), style);
118+ }
119+ }
120+
88121std::string get_task_label (const task_record& tsk) {
89122 std::string label;
90- fmt::format_to (std::back_inserter (label), " T{}" , tsk.tid );
123+ fmt::format_to (std::back_inserter (label), " T{}" , tsk.id );
91124 if (!tsk.debug_name .empty ()) { fmt::format_to (std::back_inserter (label), " \" {}\" " , utils::escape_for_dot_label (tsk.debug_name )); }
92125
93126 fmt::format_to (std::back_inserter (label), " <br/><b>{}</b>" , task_type_string (tsk.type ));
@@ -107,16 +140,15 @@ std::string make_graph_preamble(const std::string& title) { return fmt::format("
107140std::string print_task_graph (const task_recorder& recorder, const std::string& title) {
108141 std::string dot = make_graph_preamble (title);
109142
110- CELERITY_DEBUG (" print_task_graph, {} entries" , recorder.get_tasks ().size ());
143+ CELERITY_DEBUG (" print_task_graph, {} entries" , recorder.get_graph_nodes ().size ());
111144
112- for (const auto & tsk : recorder.get_tasks ()) {
113- const char * shape = tsk.type == task_type::epoch || tsk.type == task_type::horizon ? " ellipse" : " box style=rounded" ;
114- fmt::format_to (std::back_inserter (dot), " {}[shape={} label=<{}>];" , tsk.tid , shape, get_task_label (tsk));
115- for (auto d : tsk.dependencies ) {
116- fmt::format_to (std::back_inserter (dot), " {}->{}[{}];" , d.node , tsk.tid , dependency_style (d.kind , d.origin ));
117- }
145+ for (const auto & tsk : recorder.get_graph_nodes ()) {
146+ const char * shape = tsk->type == task_type::epoch || tsk->type == task_type::horizon ? " ellipse" : " box style=rounded" ;
147+ fmt::format_to (std::back_inserter (dot), " {}[shape={} label=<{}>];" , tsk->id , shape, get_task_label (*tsk));
118148 }
119149
150+ print_dependencies (recorder.get_dependencies (), dot);
151+
120152 dot += " }" ;
121153 return dot;
122154}
@@ -135,7 +167,7 @@ std::string print_command_graph(const node_id local_nid, const command_recorder&
135167 std::string main_dot;
136168 std::map<task_id, std::string> task_subgraph_dot; // this map must be ordered!
137169
138- const auto local_to_global_id = [local_nid](uint64_t id) {
170+ const auto local_to_global_id = [local_nid](auto id) -> std::string {
139171 // IDs in the DOT language may not start with a digit (unless the whole thing is a numeral)
140172 return fmt::format (" id_{}_{}" , local_nid, id);
141173 };
@@ -241,33 +273,7 @@ std::string print_command_graph(const node_id local_nid, const command_recorder&
241273 });
242274 };
243275
244- // Sort and deduplicate edges
245- struct dependency_edge {
246- command_id predecessor;
247- command_id successor;
248- };
249- struct dependency_edge_order {
250- bool operator ()(const dependency_edge& lhs, const dependency_edge& rhs) const {
251- if (lhs.predecessor < rhs.predecessor ) return true ;
252- if (lhs.predecessor > rhs.predecessor ) return false ;
253- return lhs.successor < rhs.successor ;
254- }
255- };
256- struct dependency_kind_order {
257- bool operator ()(const std::pair<dependency_kind, dependency_origin>& lhs, const std::pair<dependency_kind, dependency_origin>& rhs) const {
258- return (lhs.first == dependency_kind::true_dep && rhs.first != dependency_kind::true_dep);
259- }
260- };
261- std::map<dependency_edge, std::set<std::pair<dependency_kind, dependency_origin>, dependency_kind_order>, dependency_edge_order>
262- dependencies_by_edge; // ordered and unique
263- for (const auto & dep : recorder.get_dependencies ()) {
264- dependencies_by_edge[{dep.predecessor , dep.successor }].insert (std::pair{dep.kind , dep.origin });
265- }
266- for (const auto & [edge, meta] : dependencies_by_edge) {
267- // If there's at most two edges, take the first one (likely a true dependency followed by an anti-dependency). If there's more, bail (don't style).
268- const auto style = meta.size () <= 2 ? dependency_style (meta.begin ()->first , meta.begin ()->second ) : std::string{};
269- fmt::format_to (std::back_inserter (main_dot), " {}->{}[{}];" , local_to_global_id (edge.predecessor ), local_to_global_id (edge.successor ), style);
270- }
276+ print_dependencies<command_id>(recorder.get_dependencies (), main_dot, local_to_global_id);
271277
272278 std::string result_dot = make_graph_preamble (title);
273279 for (auto & [_, sg_dot] : task_subgraph_dot) {
0 commit comments