llvm.org GIT mirror llvm / 4dc48bf
[XRay] A graph Class for the llvm-xray graph Summary: In preparation for graph comparison and filtering, this is a library for representing graphs in LLVM. This will enable easier encapsulation and reuse of graphs in llvm-xray. Depends on D28999, D28225 Reviewers: dblaikie, dberris Reviewed By: dberris Subscribers: mgorny, llvm-commits Differential Revision: https://reviews.llvm.org/D29005 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@294717 91177308-0d34-0410-b5e6-96231b3b80d8 Dean Michael Berris 2 years ago
6 changed file(s) with 881 addition(s) and 104 deletion(s). Raw diff Collapse all Expand all
0 //===-- Graph.h - XRay Graph Class ------------------------------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // A Graph Datatype for XRay.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #ifndef LLVM_XRAY_GRAPH_T_H
14 #define LLVM_XRAY_GRAPH_T_H
15
16 #include
17 #include
18 #include
19 #include
20
21 #include "llvm/ADT/DenseMap.h"
22 #include "llvm/ADT/DenseSet.h"
23 #include "llvm/ADT/iterator.h"
24 #include "llvm/Support/Error.h"
25
26 namespace llvm {
27 namespace xray {
28
29 /// A Graph object represents a Directed Graph and is used in XRay to compute
30 /// and store function call graphs and associated statistical information.
31 ///
32 /// The graph takes in four template parameters, these are:
33 /// - VertexAttribute, this is a structure which is stored for each vertex.
34 /// Must be DefaultConstructible, CopyConstructible, CopyAssignable and
35 /// Destructible.
36 /// - EdgeAttribute, this is a structure which is stored for each edge
37 /// Must be DefaultConstructible, CopyConstructible, CopyAssignable and
38 /// Destructible.
39 /// - EdgeAttribute, this is a structure which is stored for each variable
40 /// - VI, this is a type over which DenseMapInfo is defined and is the type
41 /// used look up strings, available as VertexIdentifier.
42 /// - If the built in DenseMapInfo is not defined, provide a specialization
43 /// class type here.
44 ///
45 /// Graph is CopyConstructible, CopyAssignable, MoveConstructible and
46 /// MoveAssignable but is not EqualityComparible or LessThanComparible.
47 ///
48 /// Usage Example Graph with weighted edges and vertices:
49 /// Graph G;
50 ///
51 /// G[1] = 0;
52 /// G[2] = 2;
53 /// G[{1,2}] = 1;
54 /// G[{2,1}] = -1;
55 /// for(const auto &v : G.vertices()){
56 /// // Do something with the vertices in the graph;
57 /// }
58 /// for(const auto &e : G.edges()){
59 /// // Do something with the edges in the graph;
60 /// }
61 ///
62 /// Usage Example with StrRef keys.
63 /// Graph StrG;
64 /// char va[] = "Vertex A";
65 /// char vaa[] = "Vertex A";
66 /// char vb[] = "Vertex B"; // Vertices are referenced by String Refs.
67 /// G[va] = 0;
68 /// G[vb] = 1;
69 /// G[{va, vb}] = 1.0;
70 /// cout() << G[vaa] << " " << G[{vaa, vb}]; //prints "0 1.0".
71 ///
72 template
73 typename VI = int32_t>
74 class Graph {
75 public:
76 /// These objects are used to name edges and vertices in the graph.
77 typedef VI VertexIdentifier;
78 typedef std::pair EdgeIdentifier;
79
80 /// This type is the value_type of all iterators which range over vertices,
81 /// Determined by the Vertices DenseMap
82 using VertexValueType =
83 detail::DenseMapPair;
84
85 /// This type is the value_type of all iterators which range over edges,
86 /// Determined by the Edges DenseMap.
87 using EdgeValueType = detail::DenseMapPair;
88
89 using size_type = std::size_t;
90
91 private:
92 /// The type used for storing the EdgeAttribute for each edge in the graph
93 using EdgeMapT = DenseMap;
94
95 /// The type used for storing the VertexAttribute for each vertex in
96 /// the graph.
97 using VertexMapT = DenseMap;
98
99 /// The type used for storing the edges entering a vertex. Indexed by
100 /// the VertexIdentifier of the start of the edge. Only used to determine
101 /// where the incoming edges are, the EdgeIdentifiers are stored in an
102 /// InnerEdgeMapT.
103 using NeighborSetT = DenseSet;
104
105 /// The type storing the InnerInvGraphT corresponding to each vertex in
106 /// the graph (When a vertex has an incoming edge incident to it)
107 using NeighborLookupT = DenseMap;
108
109 private:
110 /// Stores the map from the start and end vertex of an edge to it's
111 /// EdgeAttribute
112 EdgeMapT Edges;
113
114 /// Stores the map from VertexIdentifier to VertexAttribute
115 VertexMapT Vertices;
116
117 /// Allows fast lookup for the incoming edge set of any given vertex.
118 NeighborLookupT InNeighbors;
119
120 /// Allows fast lookup for the outgoing edge set of any given vertex.
121 NeighborLookupT OutNeighbors;
122
123 /// An Iterator adapter using an InnerInvGraphT::iterator as a base iterator,
124 /// and storing the VertexIdentifier the iterator range comes from. The
125 /// dereference operator is then performed using a pointer to the graph's edge
126 /// set.
127 template
128 typename BaseIt = typename NeighborSetT::const_iterator,
129 typename T = typename std::conditional
130 EdgeValueType>::type>
131 class NeighborEdgeIteratorT
132 : public iterator_adaptor_base<
133 NeighborEdgeIteratorT, BaseIt,
134 typename std::iterator_traits::iterator_category, T> {
135 using InternalEdgeMapT =
136 typename std::conditional::type;
137
138 friend class NeighborEdgeIteratorT;
139 friend class NeighborEdgeIteratorT
140 const EdgeValueType>;
141
142 InternalEdgeMapT *MP;
143 VertexIdentifier SI;
144
145 public:
146 template
147 typename = typename std::enable_if::type>
148 operator NeighborEdgeIteratorT
149 const EdgeValueType>() const {
150 return NeighborEdgeIteratorT
151 const EdgeValueType>(this->I, MP, SI);
152 }
153
154 NeighborEdgeIteratorT() = default;
155 NeighborEdgeIteratorT(BaseIt _I, InternalEdgeMapT *_MP,
156 VertexIdentifier _SI)
157 : iterator_adaptor_base<
158 NeighborEdgeIteratorT, BaseIt,
159 typename std::iterator_traits::iterator_category, T>(_I),
160 MP(_MP), SI(_SI) {}
161
162 T &operator*() const {
163 if (!IsOut)
164 return *(MP->find({*(this->I), SI}));
165 else
166 return *(MP->find({SI, *(this->I)}));
167 }
168 };
169
170 public:
171 /// A const iterator type for iterating through the set of edges entering a
172 /// vertex.
173 ///
174 /// Has a const EdgeValueType as its value_type
175 using ConstInEdgeIterator = NeighborEdgeIteratorT;
176
177 /// An iterator type for iterating through the set of edges leaving a vertex.
178 ///
179 /// Has an EdgeValueType as its value_type
180 using InEdgeIterator = NeighborEdgeIteratorT;
181
182 /// A const iterator type for iterating through the set of edges entering a
183 /// vertex.
184 ///
185 /// Has a const EdgeValueType as its value_type
186 using ConstOutEdgeIterator = NeighborEdgeIteratorT;
187
188 /// An iterator type for iterating through the set of edges leaving a vertex.
189 ///
190 /// Has an EdgeValueType as its value_type
191 using OutEdgeIterator = NeighborEdgeIteratorT;
192
193 /// A class for ranging over the incoming edges incident to a vertex.
194 ///
195 /// Like all views in this class it provides methods to get the beginning and
196 /// past the range iterators for the range, as well as methods to determine
197 /// the number of elements in the range and whether the range is empty.
198 template class InOutEdgeView {
199 public:
200 using iterator = NeighborEdgeIteratorT;
201 using const_iterator = NeighborEdgeIteratorT;
202 using GraphT = typename std::conditional::type;
203 using InternalEdgeMapT =
204 typename std::conditional::type;
205
206 private:
207 InternalEdgeMapT &M;
208 const VertexIdentifier A;
209 const NeighborLookupT &NL;
210
211 public:
212 iterator begin() {
213 auto It = NL.find(A);
214 if (It == NL.end())
215 return iterator();
216 return iterator(It->second.begin(), &M, A);
217 }
218
219 const_iterator cbegin() const {
220 auto It = NL.find(A);
221 if (It == NL.end())
222 return const_iterator();
223 return const_iterator(It->second.begin(), &M, A);
224 }
225
226 const_iterator begin() const { return cbegin(); }
227
228 iterator end() {
229 auto It = NL.find(A);
230 if (It == NL.end())
231 return iterator();
232 return iterator(It->second.end(), &M, A);
233 }
234 const_iterator cend() const {
235 auto It = NL.find(A);
236 if (It == NL.end())
237 return const_iterator();
238 return const_iterator(It->second.end(), &M, A);
239 }
240
241 const_iterator end() const { return cend(); }
242
243 size_type size() const {
244 auto I = NL.find(A);
245 if (I == NL.end())
246 return 0;
247 else
248 return I->second.size();
249 }
250
251 bool empty() const { return NL.count(A) == 0; };
252
253 InOutEdgeView(GraphT &G, VertexIdentifier A)
254 : M(G.Edges), A(A), NL(isOut ? G.OutNeighbors : G.InNeighbors) {}
255 };
256
257 /// A const iterator type for iterating through the whole vertex set of the
258 /// graph.
259 ///
260 /// Has a const VertexValueType as its value_type
261 using ConstVertexIterator = typename VertexMapT::const_iterator;
262
263 /// An iterator type for iterating through the whole vertex set of the graph.
264 ///
265 /// Has a VertexValueType as its value_type
266 using VertexIterator = typename VertexMapT::iterator;
267
268 /// A class for ranging over the vertices in the graph.
269 ///
270 /// Like all views in this class it provides methods to get the beginning and
271 /// past the range iterators for the range, as well as methods to determine
272 /// the number of elements in the range and whether the range is empty.
273 template class VertexView {
274 public:
275 using iterator = typename std::conditional
276 VertexIterator>::type;
277 using const_iterator = ConstVertexIterator;
278 using GraphT = typename std::conditional::type;
279
280 private:
281 GraphT &G;
282
283 public:
284 iterator begin() { return G.Vertices.begin(); }
285 iterator end() { return G.Vertices.end(); }
286 const_iterator cbegin() const { return G.Vertices.cbegin(); }
287 const_iterator cend() const { return G.Vertices.cend(); }
288 const_iterator begin() const { return G.Vertices.begin(); }
289 const_iterator end() const { return G.Vertices.end(); }
290 size_type size() const { return G.Vertices.size(); }
291 bool empty() const { return G.Vertices.empty(); }
292 VertexView(GraphT &_G) : G(_G) {}
293 };
294
295 /// A const iterator for iterating through the entire edge set of the graph.
296 ///
297 /// Has a const EdgeValueType as its value_type
298 using ConstEdgeIterator = typename EdgeMapT::const_iterator;
299
300 /// An iterator for iterating through the entire edge set of the graph.
301 ///
302 /// Has an EdgeValueType as its value_type
303 using EdgeIterator = typename EdgeMapT::iterator;
304
305 /// A class for ranging over all the edges in the graph.
306 ///
307 /// Like all views in this class it provides methods to get the beginning and
308 /// past the range iterators for the range, as well as methods to determine
309 /// the number of elements in the range and whether the range is empty.
310 template class EdgeView {
311 public:
312 using iterator = typename std::conditional
313 EdgeIterator>::type;
314 using const_iterator = ConstEdgeIterator;
315 using GraphT = typename std::conditional::type;
316
317 private:
318 GraphT &G;
319
320 public:
321 iterator begin() { return G.Edges.begin(); }
322 iterator end() { return G.Edges.end(); }
323 const_iterator cbegin() const { return G.Edges.cbegin(); }
324 const_iterator cend() const { return G.Edges.cend(); }
325 const_iterator begin() const { return G.Edges.begin(); }
326 const_iterator end() const { return G.Edges.end(); }
327 size_type size() const { return G.Edges.size(); }
328 bool empty() const { return G.Edges.empty(); }
329 EdgeView(GraphT &_G) : G(_G) {}
330 };
331
332 public:
333 // TODO: implement constructor to enable Graph Initialisation.\
334 // Something like:
335 // Graph G(
336 // {1, 2, 3, 4, 5},
337 // {{1, 2}, {2, 3}, {3, 4}});
338
339 /// Empty the Graph
340 void clear() {
341 Edges.clear();
342 Vertices.clear();
343 InNeighbors.clear();
344 OutNeighbors.clear();
345 }
346
347 /// Returns a view object allowing iteration over the vertices of the graph.
348 /// also allows access to the size of the vertex set.
349 VertexView vertices() { return VertexView(*this); }
350
351 VertexView vertices() const { return VertexView(*this); }
352
353 /// Returns a view object allowing iteration over the edges of the graph.
354 /// also allows access to the size of the edge set.
355 EdgeView edges() { return EdgeView(*this); }
356
357 EdgeView edges() const { return EdgeView(*this); }
358
359 /// Returns a view object allowing iteration over the edges which start at
360 /// a vertex I.
361 InOutEdgeView outEdges(const VertexIdentifier I) {
362 return InOutEdgeView(*this, I);
363 }
364
365 InOutEdgeView outEdges(const VertexIdentifier I) const {
366 return InOutEdgeView(*this, I);
367 }
368
369 /// Returns a view object allowing iteration over the edges which point to
370 /// a vertex I.
371 InOutEdgeView inEdges(const VertexIdentifier I) {
372 return InOutEdgeView(*this, I);
373 }
374
375 InOutEdgeView inEdges(const VertexIdentifier I) const {
376 return InOutEdgeView(*this, I);
377 }
378
379 /// Looks up the vertex with identifier I, if it does not exist it default
380 /// constructs it.
381 VertexAttribute &operator[](const VertexIdentifier &I) {
382 return Vertices.FindAndConstruct(I).second;
383 }
384
385 /// Looks up the edge with identifier I, if it does not exist it default
386 /// constructs it, if it's endpoints do not exist it also default constructs
387 /// them.
388 EdgeAttribute &operator[](const EdgeIdentifier &I) {
389 auto &P = Edges.FindAndConstruct(I);
390 Vertices.FindAndConstruct(I.first);
391 Vertices.FindAndConstruct(I.second);
392 InNeighbors[I.second].insert(I.first);
393 OutNeighbors[I.first].insert(I.second);
394 return P.second;
395 }
396
397 /// Looks up a vertex with Identifier I, or an error if it does not exist.
398 Expected at(const VertexIdentifier &I) {
399 auto It = Vertices.find(I);
400 if (It == Vertices.end())
401 return make_error(
402 "Vertex Identifier Does Not Exist",
403 std::make_error_code(std::errc::invalid_argument));
404 return It->second;
405 }
406
407 Expected at(const VertexIdentifier &I) const {
408 auto It = Vertices.find(I);
409 if (It == Vertices.end())
410 return make_error(
411 "Vertex Identifier Does Not Exist",
412 std::make_error_code(std::errc::invalid_argument));
413 return It->second;
414 }
415
416 /// Looks up an edge with Identifier I, or an error if it does not exist.
417 Expected at(const EdgeIdentifier &I) {
418 auto It = Edges.find(I);
419 if (It == Edges.end())
420 return make_error(
421 "Edge Identifier Does Not Exist",
422 std::make_error_code(std::errc::invalid_argument));
423 return It->second;
424 }
425
426 Expected at(const EdgeIdentifier &I) const {
427 auto It = Edges.find(I);
428 if (It == Edges.end())
429 return make_error(
430 "Edge Identifier Does Not Exist",
431 std::make_error_code(std::errc::invalid_argument));
432 return It->second;
433 }
434
435 /// Looks for a vertex with identifier I, returns 1 if one exists, and
436 /// 0 otherwise
437 size_type count(const VertexIdentifier &I) const {
438 return Vertices.count(I);
439 }
440
441 /// Looks for an edge with Identifier I, returns 1 if one exists and 0
442 /// otherwise
443 size_type count(const EdgeIdentifier &I) const { return Edges.count(I); }
444
445 /// Inserts a vertex into the graph with Identifier Val.first, and
446 /// Attribute Val.second.
447 std::pair
448 insert(const std::pair &Val) {
449 return Vertices.insert(Val);
450 }
451
452 std::pair
453 insert(std::pair &&Val) {
454 return Vertices.insert(std::move(Val));
455 }
456
457 /// Inserts an edge into the graph with Identifier Val.first, and
458 /// Attribute Val.second. If the key is already in the map, it returns false
459 /// and doesn't update the value.
460 std::pair
461 insert(const std::pair &Val) {
462 const auto &p = Edges.insert(Val);
463 if (p.second) {
464 const auto &EI = Val.first;
465 Vertices.FindAndConstruct(EI.first);
466 Vertices.FindAndConstruct(EI.second);
467 InNeighbors[EI.second].insert(EI.first);
468 OutNeighbors[EI.first].insert(EI.second);
469 };
470
471 return p;
472 }
473
474 /// Inserts an edge into the graph with Identifier Val.first, and
475 /// Attribute Val.second. If the key is already in the map, it returns false
476 /// and doesn't update the value.
477 std::pair
478 insert(std::pair &&Val) {
479 auto EI = Val.first;
480 const auto &p = Edges.insert(std::move(Val));
481 if (p.second) {
482 Vertices.FindAndConstruct(EI.first);
483 Vertices.FindAndConstruct(EI.second);
484 InNeighbors[EI.second].insert(EI.first);
485 OutNeighbors[EI.first].insert(EI.second);
486 };
487
488 return p;
489 }
490 };
491 }
492 }
493 #endif
None //===-- xray-graph.c - XRay Function Call Graph Renderer ------------------===//
0 //===-- xray-graph.cc - XRay Function Call Graph Renderer -----------------===//
11 //
22 // The LLVM Compiler Infrastructure
33 //
2929 using namespace llvm::xray;
3030
3131 // Setup llvm-xray graph subcommand and its options.
32 static cl::SubCommand Graph("graph", "Generate function-call graph");
32 static cl::SubCommand GraphC("graph", "Generate function-call graph");
3333 static cl::opt GraphInput(cl::Positional,
3434 cl::desc(""),
35 cl::Required, cl::sub(Graph));
35 cl::Required, cl::sub(GraphC));
3636
3737 static cl::opt
3838 GraphKeepGoing("keep-going", cl::desc("Keep going on errors encountered"),
39 cl::sub(Graph), cl::init(false));
39 cl::sub(GraphC), cl::init(false));
4040 static cl::alias GraphKeepGoing2("k", cl::aliasopt(GraphKeepGoing),
4141 cl::desc("Alias for -keep-going"),
42 cl::sub(Graph));
42 cl::sub(GraphC));
4343
4444 static cl::opt
4545 GraphOutput("output", cl::value_desc("Output file"), cl::init("-"),
46 cl::desc("output file; use '-' for stdout"), cl::sub(Graph));
46 cl::desc("output file; use '-' for stdout"), cl::sub(GraphC));
4747 static cl::alias GraphOutput2("o", cl::aliasopt(GraphOutput),
48 cl::desc("Alias for -output"), cl::sub(Graph));
49
50 static cl::opt GraphInstrMap(
51 "instr_map", cl::desc("binary with the instrumrntation map, or "
52 "a separate instrumentation map"),
53 cl::value_desc("binary with xray_instr_map"), cl::sub(Graph), cl::init(""));
48 cl::desc("Alias for -output"), cl::sub(GraphC));
49
50 static cl::opt
51 GraphInstrMap("instr_map",
52 cl::desc("binary with the instrumrntation map, or "
53 "a separate instrumentation map"),
54 cl::value_desc("binary with xray_instr_map"), cl::sub(GraphC),
55 cl::init(""));
5456 static cl::alias GraphInstrMap2("m", cl::aliasopt(GraphInstrMap),
5557 cl::desc("alias for -instr_map"),
56 cl::sub(Graph));
58 cl::sub(GraphC));
5759
5860 static cl::opt GraphDeduceSiblingCalls(
5961 "deduce-sibling-calls",
6062 cl::desc("Deduce sibling calls when unrolling function call stacks"),
61 cl::sub(Graph), cl::init(false));
63 cl::sub(GraphC), cl::init(false));
6264 static cl::alias
6365 GraphDeduceSiblingCalls2("d", cl::aliasopt(GraphDeduceSiblingCalls),
6466 cl::desc("Alias for -deduce-sibling-calls"),
65 cl::sub(Graph));
67 cl::sub(GraphC));
6668
6769 static cl::opt
6870 GraphEdgeLabel("edge-label",
6971 cl::desc("Output graphs with edges labeled with this field"),
70 cl::value_desc("field"), cl::sub(Graph),
72 cl::value_desc("field"), cl::sub(GraphC),
7173 cl::init(GraphRenderer::StatType::NONE),
7274 cl::values(clEnumValN(GraphRenderer::StatType::NONE, "none",
7375 "Do not label Edges"),
8789 "sum of call durations")));
8890 static cl::alias GraphEdgeLabel2("e", cl::aliasopt(GraphEdgeLabel),
8991 cl::desc("Alias for -edge-label"),
90 cl::sub(Graph));
92 cl::sub(GraphC));
9193
9294 static cl::opt GraphVertexLabel(
9395 "vertex-label",
9496 cl::desc("Output graphs with vertices labeled with this field"),
95 cl::value_desc("field"), cl::sub(Graph),
97 cl::value_desc("field"), cl::sub(GraphC),
9698 cl::init(GraphRenderer::StatType::NONE),
9799 cl::values(clEnumValN(GraphRenderer::StatType::NONE, "none",
98100 "Do not label Edges"),
112114 "sum of call durations")));
113115 static cl::alias GraphVertexLabel2("v", cl::aliasopt(GraphVertexLabel),
114116 cl::desc("Alias for -edge-label"),
115 cl::sub(Graph));
117 cl::sub(GraphC));
116118
117119 static cl::opt GraphEdgeColorType(
118120 "color-edges",
119121 cl::desc("Output graphs with edge colors determined by this field"),
120 cl::value_desc("field"), cl::sub(Graph),
122 cl::value_desc("field"), cl::sub(GraphC),
121123 cl::init(GraphRenderer::StatType::NONE),
122124 cl::values(clEnumValN(GraphRenderer::StatType::NONE, "none",
123125 "Do not label Edges"),
137139 "sum of call durations")));
138140 static cl::alias GraphEdgeColorType2("c", cl::aliasopt(GraphEdgeColorType),
139141 cl::desc("Alias for -color-edges"),
140 cl::sub(Graph));
142 cl::sub(GraphC));
141143
142144 static cl::opt GraphVertexColorType(
143145 "color-vertices",
144146 cl::desc("Output graphs with vertex colors determined by this field"),
145 cl::value_desc("field"), cl::sub(Graph),
147 cl::value_desc("field"), cl::sub(GraphC),
146148 cl::init(GraphRenderer::StatType::NONE),
147149 cl::values(clEnumValN(GraphRenderer::StatType::NONE, "none",
148150 "Do not label Edges"),
162164 "sum of call durations")));
163165 static cl::alias GraphVertexColorType2("b", cl::aliasopt(GraphVertexColorType),
164166 cl::desc("Alias for -edge-label"),
165 cl::sub(Graph));
167 cl::sub(GraphC));
166168
167169 template T diff(T L, T R) { return std::max(L, R) - std::min(L, R); }
168170
207209 auto &ThreadStack = PerThreadFunctionStack[Record.TId];
208210 switch (Record.Type) {
209211 case RecordTypes::ENTER: {
210 if (VertexAttrs.count(Record.FuncId) == 0)
211 VertexAttrs[Record.FuncId].SymbolName =
212 FuncIdHelper.SymbolOrNumber(Record.FuncId);
212 if (G.count(Record.FuncId) == 0)
213 G[Record.FuncId].SymbolName = FuncIdHelper.SymbolOrNumber(Record.FuncId);
213214 ThreadStack.push_back({Record.FuncId, Record.TSC});
214215 break;
215216 }
216217 case RecordTypes::EXIT: {
217 // FIXME: Refactor this and the account subcommand to reducr code
218 // FIXME: Refactor this and the account subcommand to reduce code
218219 // duplication
219220 if (ThreadStack.size() == 0 || ThreadStack.back().FuncId != Record.FuncId) {
220221 if (!DeduceSiblingCalls)
229230 make_error_code(errc::invalid_argument)); // There is no matching
230231 // Function for this exit.
231232 while (ThreadStack.back().FuncId != Record.FuncId) {
232 uint64_t D = diff(ThreadStack.back().TSC, Record.TSC);
233 int32_t TopFuncId = ThreadStack.back().FuncId;
233 TimestampT D = diff(ThreadStack.back().TSC, Record.TSC);
234 VertexIdentifier TopFuncId = ThreadStack.back().FuncId;
234235 ThreadStack.pop_back();
235236 assert(ThreadStack.size() != 0);
236 auto &EA = Graph[ThreadStack.back().FuncId][TopFuncId];
237 EdgeIdentifier EI(ThreadStack.back().FuncId, TopFuncId);
238 auto &EA = G[EI];
237239 EA.Timings.push_back(D);
238240 updateStat(EA.S, D);
239 updateStat(VertexAttrs[TopFuncId].S, D);
241 updateStat(G[TopFuncId].S, D);
240242 }
241243 }
242244 uint64_t D = diff(ThreadStack.back().TSC, Record.TSC);
243245 ThreadStack.pop_back();
244 auto &V = Graph[ThreadStack.empty() ? 0 : ThreadStack.back().FuncId];
245 auto &EA = V[Record.FuncId];
246 VertexIdentifier VI = ThreadStack.empty() ? 0 : ThreadStack.back().FuncId;
247 EdgeIdentifier EI(VI, Record.FuncId);
248 auto &EA = G[EI];
246249 EA.Timings.push_back(D);
247250 updateStat(EA.S, D);
248 updateStat(VertexAttrs[Record.FuncId].S, D);
251 updateStat(G[Record.FuncId].S, D);
249252 break;
250253 }
251254 }
279282 }
280283
281284 void GraphRenderer::calculateEdgeStatistics() {
282 for (auto &V : Graph) {
283 for (auto &E : V.second) {
284 auto &A = E.second;
285 getStats(A.Timings.begin(), A.Timings.end(), A.S);
286 updateMaxStats(A.S, GraphEdgeMax);
285 assert(!G.edges().empty());
286 for (auto &E : G.edges()) {
287 auto &A = E.second;
288 assert(!A.Timings.empty());
289 assert((A.Timings[0] > 0));
290 getStats(A.Timings.begin(), A.Timings.end(), A.S);
291 assert(A.S.Sum > 0);
292 updateMaxStats(A.S, G.GraphEdgeMax);
293 }
294 }
295
296 void GraphRenderer::calculateVertexStatistics() {
297 std::vector TempTimings;
298 for (auto &V : G.vertices()) {
299 assert((V.first == 0 || G[V.first].S.Sum != 0) &&
300 "Every non-root vertex should have at least one call");
301 if (V.first != 0) {
302 for (auto &E : G.inEdges(V.first)) {
303 auto &A = E.second;
304 TempTimings.insert(TempTimings.end(), A.Timings.begin(),
305 A.Timings.end());
306 }
307 assert(!TempTimings.empty() && TempTimings[0] > 0);
308 getStats(TempTimings.begin(), TempTimings.end(), G[V.first].S);
309 updateMaxStats(G[V.first].S, G.GraphVertexMax);
310 TempTimings.clear();
287311 }
288 }
289 }
290
291 void GraphRenderer::calculateVertexStatistics() {
292 DenseMap>>
293 IncommingEdges;
294 uint64_t MaxCount = 0;
295 for (auto &V : Graph) {
296 for (auto &E : V.second) {
297 auto &IEV = IncommingEdges[E.first];
298 IEV.second.push_back(&E.second);
299 IEV.first += E.second.S.Count;
300 if (IEV.first > MaxCount)
301 MaxCount = IEV.first;
302 }
303 }
304 std::vector TempTimings;
305 TempTimings.reserve(MaxCount);
306 for (auto &V : IncommingEdges) {
307 for (auto &P : V.second.second) {
308 TempTimings.insert(TempTimings.end(), P->Timings.begin(),
309 P->Timings.end());
310 }
311 getStats(TempTimings.begin(), TempTimings.end(), VertexAttrs[V.first].S);
312 updateMaxStats(VertexAttrs[V.first].S, GraphVertexMax);
313 TempTimings.clear();
314312 }
315313 }
316314
328326
329327 // Normalises the statistics in the graph for a given TSC frequency.
330328 void GraphRenderer::normalizeStatistics(double CycleFrequency) {
331 for (auto &V : Graph) {
332 for (auto &E : V.second) {
333 auto &S = E.second.S;
334 normalizeTimeStat(S, CycleFrequency);
335 }
336 }
337 for (auto &V : VertexAttrs) {
329 for (auto &E : G.edges()) {
330 auto &S = E.second.S;
331 normalizeTimeStat(S, CycleFrequency);
332 }
333 for (auto &V : G.vertices()) {
338334 auto &S = V.second.S;
339335 normalizeTimeStat(S, CycleFrequency);
340336 }
341337
342 normalizeTimeStat(GraphEdgeMax, CycleFrequency);
343 normalizeTimeStat(GraphVertexMax, CycleFrequency);
338 normalizeTimeStat(G.GraphEdgeMax, CycleFrequency);
339 normalizeTimeStat(G.GraphVertexMax, CycleFrequency);
344340 }
345341
346342 // Returns a string containing the value of statistic field T
476472 void GraphRenderer::exportGraphAsDOT(raw_ostream &OS, const XRayFileHeader &H,
477473 StatType ET, StatType EC, StatType VT,
478474 StatType VC) {
475 G.GraphEdgeMax = {};
476 G.GraphVertexMax = {};
479477 calculateEdgeStatistics();
480478 calculateVertexStatistics();
479
481480 if (H.CycleFrequency)
482481 normalizeStatistics(H.CycleFrequency);
483482
486485 if (VT != StatType::NONE)
487486 OS << "node [shape=record];\n";
488487
489 for (const auto &V : Graph)
490 for (const auto &E : V.second) {
491 const auto &S = E.second.S;
492 OS << "F" << V.first << " -> "
493 << "F" << E.first << " [label=\"" << S.getAsString(ET) << "\"";
494 if (EC != StatType::NONE)
495 OS << " color=\"" << getColor(S.compare(EC, GraphEdgeMax)) << "\"";
496 OS << "];\n";
497 }
498
499 for (const auto &V : VertexAttrs) {
488 for (const auto &E : G.edges()) {
489 const auto &S = E.second.S;
490 OS << "F" << E.first.first << " -> "
491 << "F" << E.first.second << " [label=\"" << S.getAsString(ET) << "\"";
492 if (EC != StatType::NONE)
493 OS << " color=\"" << getColor(S.compare(EC, G.GraphEdgeMax)) << "\"";
494 OS << "];\n";
495 }
496
497 for (const auto &V : G.vertices()) {
500498 const auto &VA = V.second;
499 if (V.first == 0)
500 continue;
501501 OS << "F" << V.first << " [label=\"" << (VT != StatType::NONE ? "{" : "")
502502 << (VA.SymbolName.size() > 40 ? VA.SymbolName.substr(0, 40) + "..."
503503 : VA.SymbolName);
506506 else
507507 OS << "\"";
508508 if (VC != StatType::NONE)
509 OS << " color=\"" << getColor(VA.S.compare(VC, GraphVertexMax)) << "\"";
509 OS << " color=\"" << getColor(VA.S.compare(VC, G.GraphVertexMax)) << "\"";
510510 OS << "];\n";
511511 }
512512 OS << "}\n";
520520 //
521521 // FIXME: include additional filtering and annalysis passes to provide more
522522 // specific useful information.
523 static CommandRegistration Unused(&Graph, []() -> Error {
523 static CommandRegistration Unused(&GraphC, []() -> Error {
524524 InstrumentationMap Map;
525525 if (!GraphInstrMap.empty()) {
526526 auto InstrumentationMapOrError = loadInstrumentationMap(GraphInstrMap);
580580 handleAllErrors(std::move(E),
581581 [&](const ErrorInfoBase &E) { E.log(errs()); });
582582 }
583
584583 GR.exportGraphAsDOT(OS, Header, GraphEdgeLabel, GraphEdgeColorType,
585584 GraphVertexLabel, GraphVertexColorType);
586585 return Error::success();
2323 #include "llvm/Support/Errc.h"
2424 #include "llvm/Support/Program.h"
2525 #include "llvm/Support/raw_ostream.h"
26 #include "llvm/XRay/Graph.h"
2627 #include "llvm/XRay/Trace.h"
2728 #include "llvm/XRay/XRayRecord.h"
2829
4849 std::string getAsString(StatType T) const;
4950 double compare(StatType T, const TimeStat &Other) const;
5051 };
52 typedef uint64_t TimestampT;
5153
5254 /// An inner struct for storing edge attributes for our graph. Here the
5355 /// attributes are mainly function call statistics.
5456 ///
5557 /// FIXME: expand to contain more information eg call latencies.
56 struct EdgeAttribute {
58 struct CallStats {
5759 TimeStat S;
58 std::vector<uint64_t> Timings;
60 std::vector<TimestampT> Timings;
5961 };
6062
6163 /// An Inner Struct for storing vertex attributes, at the moment just
6264 /// SymbolNames, however in future we could store bulk function statistics.
6365 ///
6466 /// FIXME: Store more attributes based on instrumentation map.
65 struct VertexAttribute {
67 struct FunctionStats {
6668 std::string SymbolName;
6769 TimeStat S;
6870 };
7779 typedef DenseMap
7880 PerThreadFunctionStackMap;
7981
80 private:
81 /// The Graph stored in an edge-list like format, with the edges also having
82 /// An attached set of attributes.
83 DenseMap> Graph;
82 class GraphT : public Graph {
83 public:
84 TimeStat GraphEdgeMax = {};
85 TimeStat GraphVertexMax = {};
86 };
8487
85 /// Graph Vertex Attributes. These are presently stored seperate from the
86 /// main graph.
87 DenseMap VertexAttrs;
88
89 TimeStat GraphEdgeMax;
90 TimeStat GraphVertexMax;
88 GraphT G;
89 typedef typename decltype(G)::VertexIdentifier VertexIdentifier;
90 typedef typename decltype(G)::EdgeIdentifier EdgeIdentifier;
9191
9292 /// Use a Map to store the Function stack for each thread whilst building the
9393 /// graph.
9898 /// Usefull object for getting human readable Symbol Names.
9999 FuncIdConversionHelper &FuncIdHelper;
100100 bool DeduceSiblingCalls = false;
101 uint64_t CurrentMaxTSC = 0;
101 TimestampT CurrentMaxTSC = 0;
102102
103103 /// A private function to help implement the statistic generation functions;
104104 template
120120 /// Takes in a reference to a FuncIdHelper in order to have ready access to
121121 /// Symbol names.
122122 explicit GraphRenderer(FuncIdConversionHelper &FuncIdHelper, bool DSC)
123 : FuncIdHelper(FuncIdHelper), DeduceSiblingCalls(DSC) {}
123 : FuncIdHelper(FuncIdHelper), DeduceSiblingCalls(DSC) {
124 G[0] = {};
125 }
124126
125127 /// Process an Xray record and expand the graph.
126128 ///
131133 /// FIXME: Make this more robust against small irregularities.
132134 Error accountRecord(const XRayRecord &Record);
133135
134 const PerThreadFunctionStackMap getPerThreadFunctionStack() const {
136 const PerThreadFunctionStackMap &getPerThreadFunctionStack() const {
135137 return PerThreadFunctionStack;
136138 }
137139
142144 StatType EdgeColor = StatType::NONE,
143145 StatType VertexLabel = StatType::NONE,
144146 StatType VertexColor = StatType::NONE);
147
148 /// Get a reference to the internal graph.
149 const GraphT &getGraph() {
150 calculateEdgeStatistics();
151 calculateVertexStatistics();
152 return G;
153 }
145154 };
146155 }
147156 }
2323 add_subdirectory(Support)
2424 add_subdirectory(Target)
2525 add_subdirectory(Transforms)
26 add_subdirectory(XRay)
0 set(LLVM_LINK_COMPONENTS
1 Support
2 )
3
4 set(XRAYSources
5 GraphTest.cpp
6 )
7
8 add_llvm_unittest(XRayTests
9 ${XRAYSources}
10 )
11
12 add_dependencies(XRayTests intrinsics_gen)
0 //===- llvm/unittest/XRay/GraphTest.cpp - XRay Graph unit tests -*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/XRay/Graph.h"
10 #include "gtest/gtest.h"
11 #include
12 #include
13 #include
14
15 using namespace llvm;
16 using namespace xray;
17
18 namespace {
19 struct VA {
20 unsigned VA;
21 };
22 struct EA {
23 unsigned EA;
24 };
25 typedef Graph GraphT;
26 typedef typename GraphT::VertexIdentifier VI;
27 typedef typename GraphT::EdgeIdentifier EI;
28
29 // Test Fixture
30 template class GraphTest : public testing::Test {
31 protected:
32 T Graph = getTestGraph();
33
34 private:
35 static T getTestGraph() {
36 using std::make_pair;
37 typename std::remove_const::type G;
38 G.insert(make_pair(1u, VA({3u})));
39 G.insert(make_pair(2u, VA({5u})));
40 G.insert(make_pair(3u, VA({7u})));
41 G.insert(make_pair(4u, VA({11u})));
42 G.insert(make_pair(5u, VA({13u})));
43 G.insert(make_pair(6u, VA({17u})));
44
45 G.insert(std::make_pair(EI(1u, 2u), EA({3u * 5u})));
46 G.insert(std::make_pair(EI(2u, 3u), EA({5u * 7u})));
47 G.insert(std::make_pair(EI(6u, 3u), EA({2u * 7u * 17u})));
48 G.insert(std::make_pair(EI(4u, 6u), EA({11u * 17u})));
49 G.insert(std::make_pair(EI(2u, 4u), EA({5u * 11u})));
50 G.insert(std::make_pair(EI(2u, 5u), EA({5u * 13u})));
51 G.insert(std::make_pair(EI(4u, 5u), EA({11u * 13u})));
52
53 return G;
54 }
55 };
56
57 typedef ::testing::Types GraphTestTypes;
58
59 using VVT = typename GraphT::VertexValueType;
60 using EVT = typename GraphT::EdgeValueType;
61
62 TYPED_TEST_CASE(GraphTest, GraphTestTypes);
63
64 template void graphVertexTester(T &G) {
65 std::set V({1u, 2u, 3u, 4u, 5u, 6u});
66 std::vector VA({0u, 3u, 5u, 7u, 11u, 13u, 17u});
67
68 EXPECT_EQ(V.size(), G.vertices().size());
69 EXPECT_FALSE(G.vertices().empty());
70 for (unsigned u : V) {
71 auto EVV = G.at(u);
72 ASSERT_TRUE(!!EVV);
73 EXPECT_EQ(1u, G.count(u));
74 EXPECT_EQ(VA[u], EVV->VA);
75 EXPECT_NE(G.vertices().end(),
76 std::find_if(G.vertices().begin(), G.vertices().end(),
77 [&](const VVT &VV) { return VV.first == u; }));
78 consumeError(EVV.takeError());
79 }
80
81 for (auto &VVT : G.vertices()) {
82 EXPECT_EQ(1u, V.count(VVT.first));
83 EXPECT_EQ(VA[VVT.first], VVT.second.VA);
84 }
85 }
86
87 template void graphEdgeTester(T &G) {
88 std::set V({1u, 2u, 3u, 4u, 5u, 6u});
89
90 std::set> E(
91 {{1u, 2u}, {2u, 3u}, {6u, 3u}, {4u, 6u}, {2u, 4u}, {2u, 5u}, {4u, 5u}});
92 std::vector VA({0u, 3u, 5u, 7u, 11u, 13u, 17u});
93
94 EXPECT_EQ(E.size(), G.edges().size());
95 EXPECT_FALSE(G.edges().empty());
96 for (std::pair u : E) {
97 auto EEV = G.at(u);
98 ASSERT_TRUE(!!EEV);
99 EXPECT_EQ(1u, G.count(u));
100 EXPECT_EQ(VA[u.first] * VA[u.second] * ((u.first > u.second) ? 2 : 1),
101 EEV->EA);
102 auto Pred = [&](const EVT &EV) { return EV.first == u; };
103 EXPECT_NE(G.edges().end(),
104 std::find_if(G.edges().begin(), G.edges().end(), Pred));
105 consumeError(EEV.takeError());
106 }
107
108 for (auto &EV : G.edges()) {
109 EXPECT_EQ(1u, E.count(EV.first));
110 EXPECT_EQ(VA[EV.first.first] * VA[EV.first.second] *
111 ((EV.first.first > EV.first.second) ? 2 : 1),
112 EV.second.EA);
113 const auto &IE = G.inEdges(EV.first.second);
114 const auto &OE = G.outEdges(EV.first.first);
115 EXPECT_NE(IE.size(), 0u);
116 EXPECT_NE(OE.size(), 0u);
117 EXPECT_NE(IE.begin(), IE.end());
118 EXPECT_NE(OE.begin(), OE.end());
119 {
120 auto It = std::find_if(
121 G.inEdges(EV.first.second).begin(), G.inEdges(EV.first.second).end(),
122 [&](const EVT &EVI) { return EVI.first == EV.first; });
123 EXPECT_NE(G.inEdges(EV.first.second).end(), It);
124 }
125 {
126 auto It = std::find_if(
127 G.inEdges(EV.first.first).begin(), G.inEdges(EV.first.first).end(),
128 [&](const EVT &EVI) { return EVI.first == EV.first; });
129 EXPECT_EQ(G.inEdges(EV.first.first).end(), It);
130 }
131 {
132 auto It =
133 std::find_if(G.outEdges(EV.first.second).begin(),
134 G.outEdges(EV.first.second).end(),
135 [&](const EVT &EVI) { return EVI.first == EV.first; });
136 EXPECT_EQ(G.outEdges(EV.first.second).end(), It);
137 }
138 {
139 auto It = std::find_if(
140 G.outEdges(EV.first.first).begin(), G.outEdges(EV.first.first).end(),
141 [&](const EVT &EVI) { return EVI.first == EV.first; });
142 EXPECT_NE(G.outEdges(EV.first.first).end(), It);
143 }
144 }
145 }
146
147 TYPED_TEST(GraphTest, TestGraphEdge) {
148 auto &G = this->Graph;
149
150 graphEdgeTester(G);
151 }
152
153 TYPED_TEST(GraphTest, TestGraphVertex) {
154 auto &G = this->Graph;
155
156 graphVertexTester(G);
157 }
158
159 TYPED_TEST(GraphTest, TestCopyConstructor) {
160 TypeParam G(this->Graph);
161
162 graphEdgeTester(G);
163 graphVertexTester(G);
164 }
165
166 TYPED_TEST(GraphTest, TestCopyAssign) {
167 TypeParam G = this->Graph;
168
169 graphEdgeTester(G);
170 graphVertexTester(G);
171 }
172
173 TYPED_TEST(GraphTest, TestMoveConstructor) {
174 TypeParam G(std::move(this->Graph));
175
176 graphEdgeTester(G);
177 graphVertexTester(G);
178 }
179
180 // Tests the incremental Construction of a graph
181 TEST(GraphTest, TestConstruction) {
182 GraphT MG;
183 const GraphT &G = MG;
184 EXPECT_EQ(0u, G.count(0u));
185 EXPECT_EQ(0u, G.count({0u, 1u}));
186 auto VE = G.at(0);
187 auto EE = G.at({0, 0});
188 EXPECT_FALSE(VE); // G.at[0] returns an error
189 EXPECT_FALSE(EE); // G.at[{0,0}] returns an error
190 consumeError(VE.takeError());
191 consumeError(EE.takeError());
192 EXPECT_TRUE(G.vertices().empty());
193 EXPECT_TRUE(G.edges().empty());
194 EXPECT_EQ(G.vertices().begin(), G.vertices().end());
195 EXPECT_EQ(G.edges().begin(), G.edges().end());
196 }
197
198 TEST(GraphTest, TestiVertexAccessOperator) {
199 GraphT MG;
200 const GraphT &G = MG;
201
202 MG[0u] = {1u};
203 EXPECT_EQ(1u, MG[0u].VA);
204 EXPECT_EQ(1u, G.count(0u));
205 EXPECT_EQ(0u, G.count(1u));
206 EXPECT_EQ(1u, MG[0u].VA);
207 auto T = G.at(0u);
208 EXPECT_TRUE(!!T);
209 EXPECT_EQ(1u, T->VA);
210
211 EXPECT_EQ(1u, G.vertices().size());
212 EXPECT_EQ(0u, G.edges().size());
213 EXPECT_FALSE(G.vertices().empty());
214 EXPECT_TRUE(G.edges().empty());
215 EXPECT_NE(G.vertices().begin(), G.vertices().end());
216 EXPECT_EQ(G.edges().begin(), G.edges().end());
217 EXPECT_EQ(1u, G.vertices().begin()->second.VA);
218 EXPECT_EQ(0u, G.vertices().begin()->first);
219 EXPECT_EQ(0u, G.outEdges(0u).size());
220 EXPECT_TRUE(G.outEdges(0u).empty());
221 EXPECT_EQ(G.outEdges(0u).begin(), G.outEdges(0u).end());
222 EXPECT_EQ(0u, G.inEdges(0u).size());
223 EXPECT_TRUE(G.inEdges(0u).empty());
224 EXPECT_EQ(G.inEdges(0u).begin(), G.inEdges(0u).end());
225 }
226
227 TEST(GraphTest, TestEdgeAccessOperator) {
228 GraphT MG;
229 const GraphT &G = MG;
230
231 MG[{0u, 0u}] = {2u};
232 EI EdgeIdent({0u, 0u});
233 EXPECT_EQ(2u, MG[EdgeIdent].EA);
234 EXPECT_EQ(1u, G.count({0u, 0u}));
235 EXPECT_EQ(0u, G.count({0u, 1u}));
236 EXPECT_EQ(1u, G.count(0u));
237 EXPECT_NE(1u, G.count(1u));
238 auto T = G.at({0u, 0u});
239 EXPECT_TRUE(T && T->EA == 2u);
240 EXPECT_EQ(1u, G.edges().size());
241 EXPECT_EQ(1u, G.vertices().size());
242 EXPECT_FALSE(G.edges().empty());
243 EXPECT_FALSE(G.vertices().empty());
244 EXPECT_NE(G.edges().begin(), G.edges().end());
245 EXPECT_EQ(EI(0u, 0u), G.edges().begin()->first);
246 EXPECT_EQ(2u, G.edges().begin()->second.EA);
247 EXPECT_EQ(1u, G.outEdges(0u).size());
248 EXPECT_FALSE(G.outEdges(0u).empty());
249 EXPECT_NE(G.outEdges(0u).begin(), G.outEdges(0u).end());
250 EXPECT_EQ(EI(0u, 0u), G.outEdges(0u).begin()->first);
251 EXPECT_EQ(2u, G.outEdges(0u).begin()->second.EA);
252 EXPECT_EQ(++(G.outEdges(0u).begin()), G.outEdges(0u).end());
253 EXPECT_EQ(1u, G.inEdges(0u).size());
254 EXPECT_FALSE(G.inEdges(0u).empty());
255 EXPECT_NE(G.inEdges(0u).begin(), G.inEdges(0u).end());
256 EXPECT_EQ(EI(0u, 0u), G.inEdges(0u).begin()->first);
257 EXPECT_EQ(2u, G.inEdges(0u).begin()->second.EA);
258 EXPECT_EQ(++(G.inEdges(0u).begin()), G.inEdges(0u).end());
259 }
260 }