ttg 1.0.0
Template Task Graph (TTG): flowgraph-based programming model for high-performance distributed-memory algorithms
Loading...
Searching...
No Matches
dot.h
Go to the documentation of this file.
1// SPDX-License-Identifier: BSD-3-Clause
2#ifndef TTG_UTIL_DOT_H
3#define TTG_UTIL_DOT_H
4
5#include <sstream>
6#include <map>
7#include <string>
8
9#include "ttg/base/terminal.h"
10#include "ttg/traverse.h"
11
12namespace ttg {
14 class Dot : private detail::Traverse {
15 std::stringstream edges;
16 std::map<const TTBase*, std::stringstream> tt_nodes;
17 std::multimap<const TTBase *, const TTBase *> ttg_hierarchy;
18 int cluster_cnt;
19 bool disable_type;
20
21 public:
24 Dot(bool disable_type = false) : disable_type(disable_type){};
25
26 // Insert backslash before characters that dot is interpreting
27 std::string escape(const std::string &in) {
28 std::stringstream s;
29 for (char c : in) {
30 if (c == '<' || c == '>' || c == '"' || c == '|')
31 s << "\\" << c;
32 else
33 s << c;
34 }
35 return s.str();
36 }
37
38 // A unique name for the node derived from the pointer
39 std::string nodename(const TTBase *op) {
40 std::stringstream s;
41 s << "n" << (void *)op;
42 return s.str();
43 }
44
45 void build_ttg_hierarchy(const TTBase *tt) {
46 if(nullptr == tt) {
47 return;
48 }
49 auto search = ttg_hierarchy.find(tt->ttg_ptr());
50 if(search == ttg_hierarchy.end()) {
51 build_ttg_hierarchy(tt->ttg_ptr()); // make sure the parent is in the hierarchy
52 }
53 search = ttg_hierarchy.find(tt);
54 if(search == ttg_hierarchy.end()) {
55 ttg_hierarchy.insert( decltype(ttg_hierarchy)::value_type(tt->ttg_ptr(), tt) );
56 }
57 }
58
59 void ttfunc(TTBase *tt) {
60 std::string ttnm = nodename(tt);
61
62 const TTBase *ttc = reinterpret_cast<const TTBase*>(tt);
64 if(!tt->is_ttg()) {
65 std::stringstream ttss;
66
67 ttss << " " << ttnm << " [shape=record,style=filled,fillcolor=gray90,label=\"{";
68
69 size_t count = 0;
70 if (tt->get_inputs().size() > 0) ttss << "{";
71 for (auto in : tt->get_inputs()) {
72 if (in) {
73 if (count != in->get_index()) throw "ttg::Dot: lost count of ins";
74 if (disable_type) {
75 ttss << " <in" << count << ">" << escape(in->get_name());
76 } else {
77 ttss << " <in" << count << ">"
78 << " " << escape("<" + in->get_key_type_str() + "," + in->get_value_type_str() + ">") << " "
79 << escape(in->get_name());
80 }
81 } else {
82 ttss << " <in" << count << ">"
83 << " unknown ";
84 }
85 count++;
86 if (count < tt->get_inputs().size()) ttss << " |";
87 }
88 if (tt->get_inputs().size() > 0) ttss << "} |";
89
90 ttss << tt->get_name() << " ";
91
92 if (tt->get_outputs().size() > 0) ttss << " | {";
93
94 count = 0;
95 for (auto out : tt->get_outputs()) {
96 if (out) {
97 if (count != out->get_index()) throw "ttg::Dot: lost count of outs";
98 if (disable_type) {
99 ttss << " <out" << count << ">" << out->get_name();
100 } else {
101 ttss << " <out" << count << ">"
102 << " " << escape("<" + out->get_key_type_str() + "," + out->get_value_type_str() + ">") << " "
103 << out->get_name();
104 }
105 } else {
106 ttss << " <out" << count << ">"
107 << " unknown ";
108 }
109 count++;
110 if (count < tt->get_outputs().size()) ttss << " |";
111 }
112
113 if (tt->get_outputs().size() > 0) ttss << "}";
114
115 ttss << " } \"];\n";
116
117 auto search = tt_nodes.find(ttc);
118 if( tt_nodes.end() == search ) {
119 tt_nodes.insert( {ttc, std::move(ttss)} );
120 } else {
121 search->second << ttss.str();
122 }
123 } else {
124 std::cout << ttnm << " is a TTG" << std::endl;
125 }
126
127 for (auto out : tt->get_outputs()) {
128 if (out) {
129 for (auto successor : out->get_connections()) {
130 if (successor) {
131 edges << ttnm << ":out" << out->get_index() << ":s -> " << nodename(successor->get_tt()) << ":in"
132 << successor->get_index() << ":n;\n";
133 }
134 }
135 }
136 }
137 }
138
139 void infunc(TerminalBase *in) {}
140
141 void outfunc(TerminalBase *out) {}
142
143 void tree_down(int level, const TTBase *node, std::stringstream &buf) {
144 if(node == nullptr || node->is_ttg()) {
145 if(nullptr != node) {
146 buf << "subgraph cluster_" << cluster_cnt++ << " {\n";
147 }
148 auto children = ttg_hierarchy.equal_range(node);
149 for(auto child = children.first; child != children.second; child++) {
150 assert(child->first == node);
151 tree_down(level+1, child->second, buf);
152 }
153 if(nullptr != node) {
154 buf << " label = \"" << node->get_name() << "\";\n";
155 buf << "}\n";
156 }
157 } else {
158 auto child = tt_nodes.find(node);
159 if( child != tt_nodes.end()) {
160 assert(child->first == node);
161 buf << child->second.str();
162 }
163 }
164 }
165
166 public:
168 template <typename... TTBasePtrs>
169 std::enable_if_t<(std::is_convertible_v<std::remove_const_t<std::remove_reference_t<TTBasePtrs>>, TTBase *> && ...),
170 std::string>
171 operator()(TTBasePtrs &&... ops) {
172 reset();
173 std::stringstream buf;
174 buf.str(std::string());
175 buf.clear();
176
177 edges.str(std::string());
178 edges.clear();
179
180 tt_nodes.clear();
181 ttg_hierarchy.clear();
182
183 buf << "digraph G {\n";
184 buf << " ranksep=1.5;\n";
185 bool t = true;
186 t &= (traverse(std::forward<TTBasePtrs>(ops)) && ... );
187
188 cluster_cnt = 0;
189 tree_down(0, nullptr, buf);
190
191 buf << edges.str();
192 buf << "}\n";
193
194 reset();
195 std::string result = buf.str();
196 buf.str(std::string());
197 buf.clear();
198
199 return result;
200 }
201 };
202} // namespace ttg
203#endif // TTG_UTIL_DOT_H
Prints the graph to a std::string in the format understood by GraphViz's dot program.
Definition dot.h:14
void ttfunc(TTBase *tt)
Definition dot.h:59
std::enable_if_t<(std::is_convertible_v< std::remove_const_t< std::remove_reference_t< TTBasePtrs > >, TTBase * > &&...), std::string > operator()(TTBasePtrs &&... ops)
Definition dot.h:171
void infunc(TerminalBase *in)
Definition dot.h:139
void outfunc(TerminalBase *out)
Definition dot.h:141
std::string nodename(const TTBase *op)
Definition dot.h:39
std::string escape(const std::string &in)
Definition dot.h:27
void tree_down(int level, const TTBase *node, std::stringstream &buf)
Definition dot.h:143
Dot(bool disable_type=false)
Definition dot.h:24
void build_ttg_hierarchy(const TTBase *tt)
Definition dot.h:45
A base class for all template tasks.
Definition tt.h:32
const std::vector< TerminalBase * > & get_outputs() const
Returns the vector of output terminals.
Definition tt.h:228
bool is_ttg() const
Definition tt.h:211
const std::vector< TerminalBase * > & get_inputs() const
Returns the vector of input terminals.
Definition tt.h:225
const TTBase * ttg_ptr() const
Definition tt.h:207
const std::string & get_name() const
Gets the name of this operation.
Definition tt.h:219
Traverses a graph of TTs in depth-first manner following out edges.
Definition traverse.h:15
bool traverse(TTBase *tt)
Definition traverse.h:31
top-level TTG namespace contains runtime-neutral functionality
Definition keymap.h:9
int size(World world=default_execution_context())
Definition run.h:131
auto edges(inedgesT &&...args)
Make a tuple of Edges to pass to.
Definition func.h:148