blob: 23372d40f05eedc9905558aedf1870549cea6f38 [file] [log] [blame]
David Blaikie87299ad2017-01-16 20:36:26 +00001//===-- xray-graph.h - XRay Function Call Graph Renderer --------*- C++ -*-===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
David Blaikie87299ad2017-01-16 20:36:26 +00006//
7//===----------------------------------------------------------------------===//
8//
9// Generate a DOT file to represent the function call graph encountered in
10// the trace.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef XRAY_GRAPH_H
15#define XRAY_GRAPH_H
16
Dean Michael Berrisd09bf192017-01-25 07:14:43 +000017#include <string>
David Blaikie87299ad2017-01-16 20:36:26 +000018#include <vector>
19
20#include "func-id-helper.h"
Dean Michael Berrisf0cb13d2017-02-25 00:26:42 +000021#include "xray-color-helper.h"
David Blaikie87299ad2017-01-16 20:36:26 +000022#include "llvm/ADT/DenseMap.h"
23#include "llvm/ADT/SmallVector.h"
Dean Michael Berrisd09bf192017-01-25 07:14:43 +000024#include "llvm/Support/Errc.h"
Pavel Labath9778921a2017-01-17 09:39:31 +000025#include "llvm/Support/Program.h"
Dean Michael Berrisd09bf192017-01-25 07:14:43 +000026#include "llvm/Support/raw_ostream.h"
Dean Michael Berris6c97b3a2017-02-10 06:36:08 +000027#include "llvm/XRay/Graph.h"
David Blaikie87299ad2017-01-16 20:36:26 +000028#include "llvm/XRay/Trace.h"
29#include "llvm/XRay/XRayRecord.h"
30
31namespace llvm {
32namespace xray {
33
34/// A class encapsulating the logic related to analyzing XRay traces, producting
35/// Graphs from them and then exporting those graphs for review.
36class GraphRenderer {
37public:
Dean Michael Berrisd09bf192017-01-25 07:14:43 +000038 /// An enum for enumerating the various statistics gathered on latencies
39 enum class StatType { NONE, COUNT, MIN, MED, PCT90, PCT99, MAX, SUM };
40
David Blaikie87299ad2017-01-16 20:36:26 +000041 /// An inner struct for common timing statistics information
42 struct TimeStat {
Dean Michael Berrisca780b52017-04-24 05:54:33 +000043 int64_t Count;
44 double Min;
45 double Median;
46 double Pct90;
47 double Pct99;
48 double Max;
49 double Sum;
50
51 std::string getString(StatType T) const;
52 double getDouble(StatType T) const;
David Blaikie87299ad2017-01-16 20:36:26 +000053 };
Dean Michael Berrisca780b52017-04-24 05:54:33 +000054 using TimestampT = uint64_t;
David Blaikie87299ad2017-01-16 20:36:26 +000055
56 /// An inner struct for storing edge attributes for our graph. Here the
57 /// attributes are mainly function call statistics.
58 ///
59 /// FIXME: expand to contain more information eg call latencies.
Dean Michael Berris6c97b3a2017-02-10 06:36:08 +000060 struct CallStats {
David Blaikie87299ad2017-01-16 20:36:26 +000061 TimeStat S;
Dean Michael Berris6c97b3a2017-02-10 06:36:08 +000062 std::vector<TimestampT> Timings;
David Blaikie87299ad2017-01-16 20:36:26 +000063 };
64
65 /// An Inner Struct for storing vertex attributes, at the moment just
66 /// SymbolNames, however in future we could store bulk function statistics.
67 ///
68 /// FIXME: Store more attributes based on instrumentation map.
Dean Michael Berris6c97b3a2017-02-10 06:36:08 +000069 struct FunctionStats {
David Blaikie87299ad2017-01-16 20:36:26 +000070 std::string SymbolName;
Dean Michael Berrisca780b52017-04-24 05:54:33 +000071 TimeStat S = {};
David Blaikie87299ad2017-01-16 20:36:26 +000072 };
73
Dean Michael Berrisd09bf192017-01-25 07:14:43 +000074 struct FunctionAttr {
75 int32_t FuncId;
76 uint64_t TSC;
77 };
78
Dean Michael Berrisca780b52017-04-24 05:54:33 +000079 using FunctionStack = SmallVector<FunctionAttr, 4>;
Dean Michael Berrisd09bf192017-01-25 07:14:43 +000080
Alexandre Ganead1a34f32019-06-26 15:42:42 +000081 using PerThreadFunctionStackMap = DenseMap<uint32_t, FunctionStack>;
Dean Michael Berrisd09bf192017-01-25 07:14:43 +000082
Dean Michael Berris6c97b3a2017-02-10 06:36:08 +000083 class GraphT : public Graph<FunctionStats, CallStats, int32_t> {
84 public:
85 TimeStat GraphEdgeMax = {};
86 TimeStat GraphVertexMax = {};
87 };
David Blaikie87299ad2017-01-16 20:36:26 +000088
Dean Michael Berris6c97b3a2017-02-10 06:36:08 +000089 GraphT G;
Dean Michael Berrisca780b52017-04-24 05:54:33 +000090 using VertexIdentifier = typename decltype(G)::VertexIdentifier;
91 using EdgeIdentifier = decltype(G)::EdgeIdentifier;
David Blaikie87299ad2017-01-16 20:36:26 +000092
93 /// Use a Map to store the Function stack for each thread whilst building the
94 /// graph.
95 ///
96 /// FIXME: Perhaps we can Build this into LatencyAccountant? or vise versa?
Dean Michael Berrisd09bf192017-01-25 07:14:43 +000097 PerThreadFunctionStackMap PerThreadFunctionStack;
David Blaikie87299ad2017-01-16 20:36:26 +000098
99 /// Usefull object for getting human readable Symbol Names.
Dean Michael Berrisca780b52017-04-24 05:54:33 +0000100 FuncIdConversionHelper FuncIdHelper;
David Blaikie87299ad2017-01-16 20:36:26 +0000101 bool DeduceSiblingCalls = false;
Dean Michael Berris6c97b3a2017-02-10 06:36:08 +0000102 TimestampT CurrentMaxTSC = 0;
David Blaikie87299ad2017-01-16 20:36:26 +0000103
104 /// A private function to help implement the statistic generation functions;
105 template <typename U>
106 void getStats(U begin, U end, GraphRenderer::TimeStat &S);
Dean Michael Berrisd09bf192017-01-25 07:14:43 +0000107 void updateMaxStats(const TimeStat &S, TimeStat &M);
David Blaikie87299ad2017-01-16 20:36:26 +0000108
109 /// Calculates latency statistics for each edge and stores the data in the
110 /// Graph
111 void calculateEdgeStatistics();
112
113 /// Calculates latency statistics for each vertex and stores the data in the
114 /// Graph
115 void calculateVertexStatistics();
116
117 /// Normalises latency statistics for each edge and vertex by CycleFrequency;
Dean Michael Berrisd09bf192017-01-25 07:14:43 +0000118 void normalizeStatistics(double CycleFrequency);
David Blaikie87299ad2017-01-16 20:36:26 +0000119
Dean Michael Berrisf0cb13d2017-02-25 00:26:42 +0000120 /// An object to color gradients
121 ColorHelper CHelper;
122
David Blaikie87299ad2017-01-16 20:36:26 +0000123public:
124 /// Takes in a reference to a FuncIdHelper in order to have ready access to
125 /// Symbol names.
Dean Michael Berrisf0cb13d2017-02-25 00:26:42 +0000126 explicit GraphRenderer(const FuncIdConversionHelper &FuncIdHelper, bool DSC)
127 : FuncIdHelper(FuncIdHelper), DeduceSiblingCalls(DSC),
128 CHelper(ColorHelper::SequentialScheme::OrRd) {
Dean Michael Berris6c97b3a2017-02-10 06:36:08 +0000129 G[0] = {};
130 }
David Blaikie87299ad2017-01-16 20:36:26 +0000131
132 /// Process an Xray record and expand the graph.
133 ///
134 /// This Function will return true on success, or false if records are not
135 /// presented in per-thread call-tree DFS order. (That is for each thread the
136 /// Records should be in order runtime on an ideal system.)
137 ///
138 /// FIXME: Make this more robust against small irregularities.
Dean Michael Berrisd09bf192017-01-25 07:14:43 +0000139 Error accountRecord(const XRayRecord &Record);
David Blaikie87299ad2017-01-16 20:36:26 +0000140
Dean Michael Berris6c97b3a2017-02-10 06:36:08 +0000141 const PerThreadFunctionStackMap &getPerThreadFunctionStack() const {
Dean Michael Berrisd09bf192017-01-25 07:14:43 +0000142 return PerThreadFunctionStack;
143 }
David Blaikie87299ad2017-01-16 20:36:26 +0000144
Dean Michael Berrisca780b52017-04-24 05:54:33 +0000145 class Factory {
146 public:
147 bool KeepGoing;
148 bool DeduceSiblingCalls;
149 std::string InstrMap;
Dean Michael Berris01b880a2017-04-24 06:15:53 +0000150 ::llvm::xray::Trace Trace;
Dean Michael Berrisca780b52017-04-24 05:54:33 +0000151 Expected<GraphRenderer> getGraphRenderer();
152 };
153
David Blaikie87299ad2017-01-16 20:36:26 +0000154 /// Output the Embedded graph in DOT format on \p OS, labeling the edges by
155 /// \p T
Dean Michael Berrisca780b52017-04-24 05:54:33 +0000156 void exportGraphAsDOT(raw_ostream &OS, StatType EdgeLabel = StatType::NONE,
Dean Michael Berrisd09bf192017-01-25 07:14:43 +0000157 StatType EdgeColor = StatType::NONE,
158 StatType VertexLabel = StatType::NONE,
159 StatType VertexColor = StatType::NONE);
Dean Michael Berris6c97b3a2017-02-10 06:36:08 +0000160
161 /// Get a reference to the internal graph.
Dean Michael Berrisca780b52017-04-24 05:54:33 +0000162 const GraphT &getGraph() { return G; }
David Blaikie87299ad2017-01-16 20:36:26 +0000163};
Dean Michael Berrisca780b52017-04-24 05:54:33 +0000164
165/// Vector Sum of TimeStats
166inline GraphRenderer::TimeStat operator+(const GraphRenderer::TimeStat &A,
167 const GraphRenderer::TimeStat &B) {
168 return {A.Count + B.Count, A.Min + B.Min, A.Median + B.Median,
169 A.Pct90 + B.Pct90, A.Pct99 + B.Pct99, A.Max + B.Max,
170 A.Sum + B.Sum};
David Blaikie87299ad2017-01-16 20:36:26 +0000171}
Dean Michael Berrisca780b52017-04-24 05:54:33 +0000172
173/// Vector Difference of Timestats
174inline GraphRenderer::TimeStat operator-(const GraphRenderer::TimeStat &A,
175 const GraphRenderer::TimeStat &B) {
176
177 return {A.Count - B.Count, A.Min - B.Min, A.Median - B.Median,
178 A.Pct90 - B.Pct90, A.Pct99 - B.Pct99, A.Max - B.Max,
179 A.Sum - B.Sum};
David Blaikie87299ad2017-01-16 20:36:26 +0000180}
181
Dean Michael Berrisca780b52017-04-24 05:54:33 +0000182/// Scalar Diference of TimeStat and double
183inline GraphRenderer::TimeStat operator/(const GraphRenderer::TimeStat &A,
184 double B) {
185
186 return {static_cast<int64_t>(A.Count / B),
187 A.Min / B,
188 A.Median / B,
189 A.Pct90 / B,
190 A.Pct99 / B,
191 A.Max / B,
192 A.Sum / B};
193}
194
195/// Scalar product of TimeStat and Double
196inline GraphRenderer::TimeStat operator*(const GraphRenderer::TimeStat &A,
197 double B) {
198 return {static_cast<int64_t>(A.Count * B),
199 A.Min * B,
200 A.Median * B,
201 A.Pct90 * B,
202 A.Pct99 * B,
203 A.Max * B,
204 A.Sum * B};
205}
206
207/// Scalar product of double TimeStat
208inline GraphRenderer::TimeStat operator*(double A,
209 const GraphRenderer::TimeStat &B) {
210 return B * A;
211}
212
213/// Hadamard Product of TimeStats
214inline GraphRenderer::TimeStat operator*(const GraphRenderer::TimeStat &A,
215 const GraphRenderer::TimeStat &B) {
216 return {A.Count * B.Count, A.Min * B.Min, A.Median * B.Median,
217 A.Pct90 * B.Pct90, A.Pct99 * B.Pct99, A.Max * B.Max,
218 A.Sum * B.Sum};
219}
220
221/// Hadamard Division of TimeStats
222inline GraphRenderer::TimeStat operator/(const GraphRenderer::TimeStat &A,
223 const GraphRenderer::TimeStat &B) {
Dean Michael Berris0827b7f2017-04-26 01:35:23 +0000224 return {A.Count / B.Count, A.Min / B.Min, A.Median / B.Median,
225 A.Pct90 / B.Pct90, A.Pct99 / B.Pct99, A.Max / B.Max,
226 A.Sum / B.Sum};
Dean Michael Berrisca780b52017-04-24 05:54:33 +0000227}
228} // namespace xray
229} // namespace llvm
230
David Blaikie87299ad2017-01-16 20:36:26 +0000231#endif // XRAY_GRAPH_H