LLVM  4.0.0
GraphWriter.h
Go to the documentation of this file.
1 //===-- llvm/Support/GraphWriter.h - Write graph to a .dot file -*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file defines a simple interface that can be used to print out generic
11 // LLVM graphs to ".dot" files. "dot" is a tool that is part of the AT&T
12 // graphviz package (http://www.research.att.com/sw/tools/graphviz/) which can
13 // be used to turn the files output by this interface into a variety of
14 // different graphics formats.
15 //
16 // Graphs do not need to implement any interface past what is already required
17 // by the GraphTraits template, but they can choose to implement specializations
18 // of the DOTGraphTraits template if they want to customize the graphs output in
19 // any way.
20 //
21 //===----------------------------------------------------------------------===//
22 
23 #ifndef LLVM_SUPPORT_GRAPHWRITER_H
24 #define LLVM_SUPPORT_GRAPHWRITER_H
25 
26 #include "llvm/ADT/GraphTraits.h"
27 #include "llvm/ADT/Twine.h"
30 #include <vector>
31 
32 namespace llvm {
33 
34 namespace DOT { // Private functions...
35  std::string EscapeString(const std::string &Label);
36 
37  /// \brief Get a color string for this node number. Simply round-robin selects
38  /// from a reasonable number of colors.
39  StringRef getColorString(unsigned NodeNumber);
40 }
41 
42 namespace GraphProgram {
43  enum Name {
44  DOT,
45  FDP,
49  };
50 }
51 
52 bool DisplayGraph(StringRef Filename, bool wait = true,
54 
55 template<typename GraphType>
56 class GraphWriter {
57  raw_ostream &O;
58  const GraphType &G;
59 
60  typedef DOTGraphTraits<GraphType> DOTTraits;
61  typedef GraphTraits<GraphType> GTraits;
62  typedef typename GTraits::NodeRef NodeRef;
63  typedef typename GTraits::nodes_iterator node_iterator;
64  typedef typename GTraits::ChildIteratorType child_iterator;
65  DOTTraits DTraits;
66 
67  static_assert(std::is_pointer<NodeRef>::value,
68  "FIXME: Currently GraphWriter requires the NodeRef type to be "
69  "a pointer.\nThe pointer usage should be moved to "
70  "DOTGraphTraits, and removed from GraphWriter itself.");
71 
72  // Writes the edge labels of the node to O and returns true if there are any
73  // edge labels not equal to the empty string "".
74  bool getEdgeSourceLabels(raw_ostream &O, NodeRef Node) {
75  child_iterator EI = GTraits::child_begin(Node);
76  child_iterator EE = GTraits::child_end(Node);
77  bool hasEdgeSourceLabels = false;
78 
79  for (unsigned i = 0; EI != EE && i != 64; ++EI, ++i) {
80  std::string label = DTraits.getEdgeSourceLabel(Node, EI);
81 
82  if (label.empty())
83  continue;
84 
85  hasEdgeSourceLabels = true;
86 
87  if (i)
88  O << "|";
89 
90  O << "<s" << i << ">" << DOT::EscapeString(label);
91  }
92 
93  if (EI != EE && hasEdgeSourceLabels)
94  O << "|<s64>truncated...";
95 
96  return hasEdgeSourceLabels;
97  }
98 
99 public:
100  GraphWriter(raw_ostream &o, const GraphType &g, bool SN) : O(o), G(g) {
101  DTraits = DOTTraits(SN);
102  }
103 
104  void writeGraph(const std::string &Title = "") {
105  // Output the header for the graph...
106  writeHeader(Title);
107 
108  // Emit all of the nodes in the graph...
109  writeNodes();
110 
111  // Output any customizations on the graph
113 
114  // Output the end of the graph
115  writeFooter();
116  }
117 
118  void writeHeader(const std::string &Title) {
119  std::string GraphName = DTraits.getGraphName(G);
120 
121  if (!Title.empty())
122  O << "digraph \"" << DOT::EscapeString(Title) << "\" {\n";
123  else if (!GraphName.empty())
124  O << "digraph \"" << DOT::EscapeString(GraphName) << "\" {\n";
125  else
126  O << "digraph unnamed {\n";
127 
128  if (DTraits.renderGraphFromBottomUp())
129  O << "\trankdir=\"BT\";\n";
130 
131  if (!Title.empty())
132  O << "\tlabel=\"" << DOT::EscapeString(Title) << "\";\n";
133  else if (!GraphName.empty())
134  O << "\tlabel=\"" << DOT::EscapeString(GraphName) << "\";\n";
135  O << DTraits.getGraphProperties(G);
136  O << "\n";
137  }
138 
139  void writeFooter() {
140  // Finish off the graph
141  O << "}\n";
142  }
143 
144  void writeNodes() {
145  // Loop over the graph, printing it out...
146  for (node_iterator I = GTraits::nodes_begin(G), E = GTraits::nodes_end(G);
147  I != E; ++I)
148  if (!isNodeHidden(*I))
149  writeNode(*I);
150  }
151 
152  bool isNodeHidden(NodeRef Node) {
153  return DTraits.isNodeHidden(Node);
154  }
155 
156  void writeNode(NodeRef Node) {
157  std::string NodeAttributes = DTraits.getNodeAttributes(Node, G);
158 
159  O << "\tNode" << static_cast<const void*>(Node) << " [shape=record,";
160  if (!NodeAttributes.empty()) O << NodeAttributes << ",";
161  O << "label=\"{";
162 
163  if (!DTraits.renderGraphFromBottomUp()) {
164  O << DOT::EscapeString(DTraits.getNodeLabel(Node, G));
165 
166  // If we should include the address of the node in the label, do so now.
167  std::string Id = DTraits.getNodeIdentifierLabel(Node, G);
168  if (!Id.empty())
169  O << "|" << DOT::EscapeString(Id);
170 
171  std::string NodeDesc = DTraits.getNodeDescription(Node, G);
172  if (!NodeDesc.empty())
173  O << "|" << DOT::EscapeString(NodeDesc);
174  }
175 
176  std::string edgeSourceLabels;
177  raw_string_ostream EdgeSourceLabels(edgeSourceLabels);
178  bool hasEdgeSourceLabels = getEdgeSourceLabels(EdgeSourceLabels, Node);
179 
180  if (hasEdgeSourceLabels) {
181  if (!DTraits.renderGraphFromBottomUp()) O << "|";
182 
183  O << "{" << EdgeSourceLabels.str() << "}";
184 
185  if (DTraits.renderGraphFromBottomUp()) O << "|";
186  }
187 
188  if (DTraits.renderGraphFromBottomUp()) {
189  O << DOT::EscapeString(DTraits.getNodeLabel(Node, G));
190 
191  // If we should include the address of the node in the label, do so now.
192  std::string Id = DTraits.getNodeIdentifierLabel(Node, G);
193  if (!Id.empty())
194  O << "|" << DOT::EscapeString(Id);
195 
196  std::string NodeDesc = DTraits.getNodeDescription(Node, G);
197  if (!NodeDesc.empty())
198  O << "|" << DOT::EscapeString(NodeDesc);
199  }
200 
201  if (DTraits.hasEdgeDestLabels()) {
202  O << "|{";
203 
204  unsigned i = 0, e = DTraits.numEdgeDestLabels(Node);
205  for (; i != e && i != 64; ++i) {
206  if (i) O << "|";
207  O << "<d" << i << ">"
208  << DOT::EscapeString(DTraits.getEdgeDestLabel(Node, i));
209  }
210 
211  if (i != e)
212  O << "|<d64>truncated...";
213  O << "}";
214  }
215 
216  O << "}\"];\n"; // Finish printing the "node" line
217 
218  // Output all of the edges now
219  child_iterator EI = GTraits::child_begin(Node);
220  child_iterator EE = GTraits::child_end(Node);
221  for (unsigned i = 0; EI != EE && i != 64; ++EI, ++i)
222  if (!DTraits.isNodeHidden(*EI))
223  writeEdge(Node, i, EI);
224  for (; EI != EE; ++EI)
225  if (!DTraits.isNodeHidden(*EI))
226  writeEdge(Node, 64, EI);
227  }
228 
229  void writeEdge(NodeRef Node, unsigned edgeidx, child_iterator EI) {
230  if (NodeRef TargetNode = *EI) {
231  int DestPort = -1;
232  if (DTraits.edgeTargetsEdgeSource(Node, EI)) {
233  child_iterator TargetIt = DTraits.getEdgeTarget(Node, EI);
234 
235  // Figure out which edge this targets...
236  unsigned Offset =
237  (unsigned)std::distance(GTraits::child_begin(TargetNode), TargetIt);
238  DestPort = static_cast<int>(Offset);
239  }
240 
241  if (DTraits.getEdgeSourceLabel(Node, EI).empty())
242  edgeidx = -1;
243 
244  emitEdge(static_cast<const void*>(Node), edgeidx,
245  static_cast<const void*>(TargetNode), DestPort,
246  DTraits.getEdgeAttributes(Node, EI, G));
247  }
248  }
249 
250  /// emitSimpleNode - Outputs a simple (non-record) node
251  void emitSimpleNode(const void *ID, const std::string &Attr,
252  const std::string &Label, unsigned NumEdgeSources = 0,
253  const std::vector<std::string> *EdgeSourceLabels = nullptr) {
254  O << "\tNode" << ID << "[ ";
255  if (!Attr.empty())
256  O << Attr << ",";
257  O << " label =\"";
258  if (NumEdgeSources) O << "{";
259  O << DOT::EscapeString(Label);
260  if (NumEdgeSources) {
261  O << "|{";
262 
263  for (unsigned i = 0; i != NumEdgeSources; ++i) {
264  if (i) O << "|";
265  O << "<s" << i << ">";
266  if (EdgeSourceLabels) O << DOT::EscapeString((*EdgeSourceLabels)[i]);
267  }
268  O << "}}";
269  }
270  O << "\"];\n";
271  }
272 
273  /// emitEdge - Output an edge from a simple node into the graph...
274  void emitEdge(const void *SrcNodeID, int SrcNodePort,
275  const void *DestNodeID, int DestNodePort,
276  const std::string &Attrs) {
277  if (SrcNodePort > 64) return; // Eminating from truncated part?
278  if (DestNodePort > 64) DestNodePort = 64; // Targeting the truncated part?
279 
280  O << "\tNode" << SrcNodeID;
281  if (SrcNodePort >= 0)
282  O << ":s" << SrcNodePort;
283  O << " -> Node" << DestNodeID;
284  if (DestNodePort >= 0 && DTraits.hasEdgeDestLabels())
285  O << ":d" << DestNodePort;
286 
287  if (!Attrs.empty())
288  O << "[" << Attrs << "]";
289  O << ";\n";
290  }
291 
292  /// getOStream - Get the raw output stream into the graph file. Useful to
293  /// write fancy things using addCustomGraphFeatures().
295  return O;
296  }
297 };
298 
299 template<typename GraphType>
300 raw_ostream &WriteGraph(raw_ostream &O, const GraphType &G,
301  bool ShortNames = false,
302  const Twine &Title = "") {
303  // Start the graph emission process...
304  GraphWriter<GraphType> W(O, G, ShortNames);
305 
306  // Emit the graph.
307  W.writeGraph(Title.str());
308 
309  return O;
310 }
311 
312 std::string createGraphFilename(const Twine &Name, int &FD);
313 
314 template <typename GraphType>
315 std::string WriteGraph(const GraphType &G, const Twine &Name,
316  bool ShortNames = false, const Twine &Title = "") {
317  int FD;
318  // Windows can't always handle long paths, so limit the length of the name.
319  std::string N = Name.str();
320  N = N.substr(0, std::min<std::size_t>(N.size(), 140));
321  std::string Filename = createGraphFilename(N, FD);
322  raw_fd_ostream O(FD, /*shouldClose=*/ true);
323 
324  if (FD == -1) {
325  errs() << "error opening file '" << Filename << "' for writing!\n";
326  return "";
327  }
328 
329  llvm::WriteGraph(O, G, ShortNames, Title);
330  errs() << " done. \n";
331 
332  return Filename;
333 }
334 
335 /// ViewGraph - Emit a dot graph, run 'dot', run gv on the postscript file,
336 /// then cleanup. For use from the debugger.
337 ///
338 template<typename GraphType>
339 void ViewGraph(const GraphType &G, const Twine &Name,
340  bool ShortNames = false, const Twine &Title = "",
342  std::string Filename = llvm::WriteGraph(G, Name, ShortNames, Title);
343 
344  if (Filename.empty())
345  return;
346 
347  DisplayGraph(Filename, false, Program);
348 }
349 
350 } // End llvm namespace
351 
352 #endif
static std::string getNodeDescription(const void *, const GraphType &)
static EdgeIter getEdgeTarget(const void *, EdgeIter I)
getEdgeTarget - If edgeTargetsEdgeSource returns true, this method is called to determine which outgo...
raw_ostream & errs()
This returns a reference to a raw_ostream for standard error.
size_t i
static void addCustomGraphFeatures(const GraphType &, GraphWriter &)
addCustomGraphFeatures - If a graph is made up of more than just straight-forward nodes and edges...
static std::string getNodeIdentifierLabel(const void *, const GraphType &)
void emitSimpleNode(const void *ID, const std::string &Attr, const std::string &Label, unsigned NumEdgeSources=0, const std::vector< std::string > *EdgeSourceLabels=nullptr)
emitSimpleNode - Outputs a simple (non-record) node
Definition: GraphWriter.h:251
static std::string getEdgeAttributes(const void *, EdgeIter, const GraphType &)
If you want to override the dot attributes printed for a particular edge, override this method...
raw_ostream & getOStream()
getOStream - Get the raw output stream into the graph file.
Definition: GraphWriter.h:294
std::string str() const
Return the twine contents as a std::string.
Definition: Twine.cpp:17
static std::string getEdgeSourceLabel(const void *, EdgeIter)
getEdgeSourceLabel - If you want to label the edge source itself, implement this method.
static bool hasEdgeDestLabels()
hasEdgeDestLabels - If this function returns true, the graph is able to provide labels for edge desti...
static unsigned numEdgeDestLabels(const void *)
numEdgeDestLabels - If hasEdgeDestLabels, this function returns the number of incoming edge labels th...
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:81
static bool edgeTargetsEdgeSource(const void *, EdgeIter)
edgeTargetsEdgeSource - This method returns true if this outgoing edge should actually target another...
GraphWriter(raw_ostream &o, const GraphType &g, bool SN)
Definition: GraphWriter.h:100
std::string getNodeLabel(const void *, const GraphType &)
getNodeLabel - Given a node and a pointer to the top level graph, return the label to print in the no...
raw_ostream & WriteGraph(raw_ostream &O, const GraphType &G, bool ShortNames=false, const Twine &Title="")
Definition: GraphWriter.h:300
static GCRegistry::Add< CoreCLRGC > E("coreclr","CoreCLR-compatible GC")
GraphType::UnknownGraphTypeError NodeRef
Definition: GraphTraits.h:61
std::string EscapeString(const std::string &Label)
Definition: GraphWriter.cpp:24
uint32_t Offset
void ViewGraph(const GraphType &G, const Twine &Name, bool ShortNames=false, const Twine &Title="", GraphProgram::Name Program=GraphProgram::DOT)
ViewGraph - Emit a dot graph, run 'dot', run gv on the postscript file, then cleanup.
Definition: GraphWriter.h:339
bool isNodeHidden(NodeRef Node)
Definition: GraphWriter.h:152
void writeNode(NodeRef Node)
Definition: GraphWriter.h:156
std::string & str()
Flushes the stream contents to the target string and returns the string's reference.
Definition: raw_ostream.h:479
std::string createGraphFilename(const Twine &Name, int &FD)
Definition: GraphWriter.cpp:67
static std::string getEdgeDestLabel(const void *, unsigned)
getEdgeDestLabel - If hasEdgeDestLabels, this function returns the incoming edge label with the given...
static std::string getGraphProperties(const GraphType &)
getGraphProperties - Return any custom properties that should be included in the top level graph stru...
const DataFlowGraph & G
Definition: RDFGraph.cpp:206
void writeHeader(const std::string &Title)
Definition: GraphWriter.h:118
StringRef getColorString(unsigned NodeNumber)
Get a color string for this node number.
Definition: GraphWriter.cpp:58
static std::string getNodeAttributes(const void *, const GraphType &)
If you want to specify custom node attributes, this is the place to do so.
static bool isNodeHidden(const void *)
isNodeHidden - If the function returns true, the given node is not displayed in the graph...
void writeEdge(NodeRef Node, unsigned edgeidx, child_iterator EI)
Definition: GraphWriter.h:229
A raw_ostream that writes to a file descriptor.
Definition: raw_ostream.h:357
bool DisplayGraph(StringRef Filename, bool wait=true, GraphProgram::Name program=GraphProgram::DOT)
#define I(x, y, z)
Definition: MD5.cpp:54
#define N
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:463
This class implements an extremely fast bulk output stream that can only output to a stream...
Definition: raw_ostream.h:44
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:47
void writeGraph(const std::string &Title="")
Definition: GraphWriter.h:104
static bool renderGraphFromBottomUp()
renderGraphFromBottomUp - If this function returns true, the graph is emitted bottom-up instead of to...
static std::string getGraphName(const GraphType &)
getGraphName - Return the label for the graph as a whole.
void emitEdge(const void *SrcNodeID, int SrcNodePort, const void *DestNodeID, int DestNodePort, const std::string &Attrs)
emitEdge - Output an edge from a simple node into the graph...
Definition: GraphWriter.h:274