xray-graph.h 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. //===-- xray-graph.h - XRay Function Call Graph Renderer --------*- C++ -*-===//
  2. //
  3. // 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
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // Generate a DOT file to represent the function call graph encountered in
  10. // the trace.
  11. //
  12. //===----------------------------------------------------------------------===//
  13. #ifndef XRAY_GRAPH_H
  14. #define XRAY_GRAPH_H
  15. #include <string>
  16. #include <vector>
  17. #include "func-id-helper.h"
  18. #include "xray-color-helper.h"
  19. #include "llvm/ADT/DenseMap.h"
  20. #include "llvm/ADT/SmallVector.h"
  21. #include "llvm/Support/Errc.h"
  22. #include "llvm/Support/Program.h"
  23. #include "llvm/Support/raw_ostream.h"
  24. #include "llvm/XRay/Graph.h"
  25. #include "llvm/XRay/Trace.h"
  26. #include "llvm/XRay/XRayRecord.h"
  27. namespace llvm {
  28. namespace xray {
  29. /// A class encapsulating the logic related to analyzing XRay traces, producting
  30. /// Graphs from them and then exporting those graphs for review.
  31. class GraphRenderer {
  32. public:
  33. /// An enum for enumerating the various statistics gathered on latencies
  34. enum class StatType { NONE, COUNT, MIN, MED, PCT90, PCT99, MAX, SUM };
  35. /// An inner struct for common timing statistics information
  36. struct TimeStat {
  37. int64_t Count;
  38. double Min;
  39. double Median;
  40. double Pct90;
  41. double Pct99;
  42. double Max;
  43. double Sum;
  44. std::string getString(StatType T) const;
  45. double getDouble(StatType T) const;
  46. };
  47. using TimestampT = uint64_t;
  48. /// An inner struct for storing edge attributes for our graph. Here the
  49. /// attributes are mainly function call statistics.
  50. ///
  51. /// FIXME: expand to contain more information eg call latencies.
  52. struct CallStats {
  53. TimeStat S;
  54. std::vector<TimestampT> Timings;
  55. };
  56. /// An Inner Struct for storing vertex attributes, at the moment just
  57. /// SymbolNames, however in future we could store bulk function statistics.
  58. ///
  59. /// FIXME: Store more attributes based on instrumentation map.
  60. struct FunctionStats {
  61. std::string SymbolName;
  62. TimeStat S = {};
  63. };
  64. struct FunctionAttr {
  65. int32_t FuncId;
  66. uint64_t TSC;
  67. };
  68. using FunctionStack = SmallVector<FunctionAttr, 4>;
  69. using PerThreadFunctionStackMap = DenseMap<uint32_t, FunctionStack>;
  70. class GraphT : public Graph<FunctionStats, CallStats, int32_t> {
  71. public:
  72. TimeStat GraphEdgeMax = {};
  73. TimeStat GraphVertexMax = {};
  74. };
  75. GraphT G;
  76. using VertexIdentifier = typename decltype(G)::VertexIdentifier;
  77. using EdgeIdentifier = decltype(G)::EdgeIdentifier;
  78. /// Use a Map to store the Function stack for each thread whilst building the
  79. /// graph.
  80. ///
  81. /// FIXME: Perhaps we can Build this into LatencyAccountant? or vise versa?
  82. PerThreadFunctionStackMap PerThreadFunctionStack;
  83. /// Usefull object for getting human readable Symbol Names.
  84. FuncIdConversionHelper FuncIdHelper;
  85. bool DeduceSiblingCalls = false;
  86. TimestampT CurrentMaxTSC = 0;
  87. /// A private function to help implement the statistic generation functions;
  88. template <typename U>
  89. void getStats(U begin, U end, GraphRenderer::TimeStat &S);
  90. void updateMaxStats(const TimeStat &S, TimeStat &M);
  91. /// Calculates latency statistics for each edge and stores the data in the
  92. /// Graph
  93. void calculateEdgeStatistics();
  94. /// Calculates latency statistics for each vertex and stores the data in the
  95. /// Graph
  96. void calculateVertexStatistics();
  97. /// Normalises latency statistics for each edge and vertex by CycleFrequency;
  98. void normalizeStatistics(double CycleFrequency);
  99. /// An object to color gradients
  100. ColorHelper CHelper;
  101. public:
  102. /// Takes in a reference to a FuncIdHelper in order to have ready access to
  103. /// Symbol names.
  104. explicit GraphRenderer(const FuncIdConversionHelper &FuncIdHelper, bool DSC)
  105. : FuncIdHelper(FuncIdHelper), DeduceSiblingCalls(DSC),
  106. CHelper(ColorHelper::SequentialScheme::OrRd) {
  107. G[0] = {};
  108. }
  109. /// Process an Xray record and expand the graph.
  110. ///
  111. /// This Function will return true on success, or false if records are not
  112. /// presented in per-thread call-tree DFS order. (That is for each thread the
  113. /// Records should be in order runtime on an ideal system.)
  114. ///
  115. /// FIXME: Make this more robust against small irregularities.
  116. Error accountRecord(const XRayRecord &Record);
  117. const PerThreadFunctionStackMap &getPerThreadFunctionStack() const {
  118. return PerThreadFunctionStack;
  119. }
  120. class Factory {
  121. public:
  122. bool KeepGoing;
  123. bool DeduceSiblingCalls;
  124. std::string InstrMap;
  125. ::llvm::xray::Trace Trace;
  126. Expected<GraphRenderer> getGraphRenderer();
  127. };
  128. /// Output the Embedded graph in DOT format on \p OS, labeling the edges by
  129. /// \p T
  130. void exportGraphAsDOT(raw_ostream &OS, StatType EdgeLabel = StatType::NONE,
  131. StatType EdgeColor = StatType::NONE,
  132. StatType VertexLabel = StatType::NONE,
  133. StatType VertexColor = StatType::NONE);
  134. /// Get a reference to the internal graph.
  135. const GraphT &getGraph() { return G; }
  136. };
  137. /// Vector Sum of TimeStats
  138. inline GraphRenderer::TimeStat operator+(const GraphRenderer::TimeStat &A,
  139. const GraphRenderer::TimeStat &B) {
  140. return {A.Count + B.Count, A.Min + B.Min, A.Median + B.Median,
  141. A.Pct90 + B.Pct90, A.Pct99 + B.Pct99, A.Max + B.Max,
  142. A.Sum + B.Sum};
  143. }
  144. /// Vector Difference of Timestats
  145. inline GraphRenderer::TimeStat operator-(const GraphRenderer::TimeStat &A,
  146. const GraphRenderer::TimeStat &B) {
  147. return {A.Count - B.Count, A.Min - B.Min, A.Median - B.Median,
  148. A.Pct90 - B.Pct90, A.Pct99 - B.Pct99, A.Max - B.Max,
  149. A.Sum - B.Sum};
  150. }
  151. /// Scalar Diference of TimeStat and double
  152. inline GraphRenderer::TimeStat operator/(const GraphRenderer::TimeStat &A,
  153. double B) {
  154. return {static_cast<int64_t>(A.Count / B),
  155. A.Min / B,
  156. A.Median / B,
  157. A.Pct90 / B,
  158. A.Pct99 / B,
  159. A.Max / B,
  160. A.Sum / B};
  161. }
  162. /// Scalar product of TimeStat and Double
  163. inline GraphRenderer::TimeStat operator*(const GraphRenderer::TimeStat &A,
  164. double B) {
  165. return {static_cast<int64_t>(A.Count * B),
  166. A.Min * B,
  167. A.Median * B,
  168. A.Pct90 * B,
  169. A.Pct99 * B,
  170. A.Max * B,
  171. A.Sum * B};
  172. }
  173. /// Scalar product of double TimeStat
  174. inline GraphRenderer::TimeStat operator*(double A,
  175. const GraphRenderer::TimeStat &B) {
  176. return B * A;
  177. }
  178. /// Hadamard Product of TimeStats
  179. inline GraphRenderer::TimeStat operator*(const GraphRenderer::TimeStat &A,
  180. const GraphRenderer::TimeStat &B) {
  181. return {A.Count * B.Count, A.Min * B.Min, A.Median * B.Median,
  182. A.Pct90 * B.Pct90, A.Pct99 * B.Pct99, A.Max * B.Max,
  183. A.Sum * B.Sum};
  184. }
  185. /// Hadamard Division of TimeStats
  186. inline GraphRenderer::TimeStat operator/(const GraphRenderer::TimeStat &A,
  187. const GraphRenderer::TimeStat &B) {
  188. return {A.Count / B.Count, A.Min / B.Min, A.Median / B.Median,
  189. A.Pct90 / B.Pct90, A.Pct99 / B.Pct99, A.Max / B.Max,
  190. A.Sum / B.Sum};
  191. }
  192. } // namespace xray
  193. } // namespace llvm
  194. #endif // XRAY_GRAPH_H