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