xray-graph.h revision 317017
1317017Sdim//===-- xray-graph.h - XRay Function Call Graph Renderer --------*- C++ -*-===//
2317017Sdim//
3317017Sdim//                     The LLVM Compiler Infrastructure
4317017Sdim//
5317017Sdim// This file is distributed under the University of Illinois Open Source
6317017Sdim// License. See LICENSE.TXT for details.
7317017Sdim//
8317017Sdim//===----------------------------------------------------------------------===//
9317017Sdim//
10317017Sdim// Generate a DOT file to represent the function call graph encountered in
11317017Sdim// the trace.
12317017Sdim//
13317017Sdim//===----------------------------------------------------------------------===//
14317017Sdim
15317017Sdim#ifndef XRAY_GRAPH_H
16317017Sdim#define XRAY_GRAPH_H
17317017Sdim
18317017Sdim#include <string>
19317017Sdim#include <vector>
20317017Sdim
21317017Sdim#include "func-id-helper.h"
22317017Sdim#include "xray-color-helper.h"
23317017Sdim#include "llvm/ADT/DenseMap.h"
24317017Sdim#include "llvm/ADT/SmallVector.h"
25317017Sdim#include "llvm/Support/Errc.h"
26317017Sdim#include "llvm/Support/Program.h"
27317017Sdim#include "llvm/Support/raw_ostream.h"
28317017Sdim#include "llvm/XRay/Graph.h"
29317017Sdim#include "llvm/XRay/Trace.h"
30317017Sdim#include "llvm/XRay/XRayRecord.h"
31317017Sdim
32317017Sdimnamespace llvm {
33317017Sdimnamespace xray {
34317017Sdim
35317017Sdim/// A class encapsulating the logic related to analyzing XRay traces, producting
36317017Sdim/// Graphs from them and then exporting those graphs for review.
37317017Sdimclass GraphRenderer {
38317017Sdimpublic:
39317017Sdim  /// An enum for enumerating the various statistics gathered on latencies
40317017Sdim  enum class StatType { NONE, COUNT, MIN, MED, PCT90, PCT99, MAX, SUM };
41317017Sdim
42317017Sdim  /// An inner struct for common timing statistics information
43317017Sdim  struct TimeStat {
44317017Sdim    uint64_t Count = 0;
45317017Sdim    double Min = 0;
46317017Sdim    double Median = 0;
47317017Sdim    double Pct90 = 0;
48317017Sdim    double Pct99 = 0;
49317017Sdim    double Max = 0;
50317017Sdim    double Sum = 0;
51317017Sdim    std::string getAsString(StatType T) const;
52317017Sdim    double compare(StatType T, const TimeStat &Other) const;
53317017Sdim  };
54317017Sdim  typedef uint64_t TimestampT;
55317017Sdim
56317017Sdim  /// An inner struct for storing edge attributes for our graph. Here the
57317017Sdim  /// attributes are mainly function call statistics.
58317017Sdim  ///
59317017Sdim  /// FIXME: expand to contain more information eg call latencies.
60317017Sdim  struct CallStats {
61317017Sdim    TimeStat S;
62317017Sdim    std::vector<TimestampT> Timings;
63317017Sdim  };
64317017Sdim
65317017Sdim  /// An Inner Struct for storing vertex attributes, at the moment just
66317017Sdim  /// SymbolNames, however in future we could store bulk function statistics.
67317017Sdim  ///
68317017Sdim  /// FIXME: Store more attributes based on instrumentation map.
69317017Sdim  struct FunctionStats {
70317017Sdim    std::string SymbolName;
71317017Sdim    TimeStat S;
72317017Sdim  };
73317017Sdim
74317017Sdim  struct FunctionAttr {
75317017Sdim    int32_t FuncId;
76317017Sdim    uint64_t TSC;
77317017Sdim  };
78317017Sdim
79317017Sdim  typedef SmallVector<FunctionAttr, 4> FunctionStack;
80317017Sdim
81317017Sdim  typedef DenseMap<llvm::sys::ProcessInfo::ProcessId, FunctionStack>
82317017Sdim      PerThreadFunctionStackMap;
83317017Sdim
84317017Sdim  class GraphT : public Graph<FunctionStats, CallStats, int32_t> {
85317017Sdim  public:
86317017Sdim    TimeStat GraphEdgeMax = {};
87317017Sdim    TimeStat GraphVertexMax = {};
88317017Sdim  };
89317017Sdim
90317017Sdim  GraphT G;
91317017Sdim  typedef typename decltype(G)::VertexIdentifier VertexIdentifier;
92317017Sdim  typedef typename decltype(G)::EdgeIdentifier EdgeIdentifier;
93317017Sdim
94317017Sdim  /// Use a Map to store the Function stack for each thread whilst building the
95317017Sdim  /// graph.
96317017Sdim  ///
97317017Sdim  /// FIXME: Perhaps we can Build this into LatencyAccountant? or vise versa?
98317017Sdim  PerThreadFunctionStackMap PerThreadFunctionStack;
99317017Sdim
100317017Sdim  /// Usefull object for getting human readable Symbol Names.
101317017Sdim  const FuncIdConversionHelper &FuncIdHelper;
102317017Sdim  bool DeduceSiblingCalls = false;
103317017Sdim  TimestampT CurrentMaxTSC = 0;
104317017Sdim
105317017Sdim  /// A private function to help implement the statistic generation functions;
106317017Sdim  template <typename U>
107317017Sdim  void getStats(U begin, U end, GraphRenderer::TimeStat &S);
108317017Sdim  void updateMaxStats(const TimeStat &S, TimeStat &M);
109317017Sdim
110317017Sdim  /// Calculates latency statistics for each edge and stores the data in the
111317017Sdim  /// Graph
112317017Sdim  void calculateEdgeStatistics();
113317017Sdim
114317017Sdim  /// Calculates latency statistics for each vertex and stores the data in the
115317017Sdim  /// Graph
116317017Sdim  void calculateVertexStatistics();
117317017Sdim
118317017Sdim  /// Normalises latency statistics for each edge and vertex by CycleFrequency;
119317017Sdim  void normalizeStatistics(double CycleFrequency);
120317017Sdim
121317017Sdim  /// An object to color gradients
122317017Sdim  ColorHelper CHelper;
123317017Sdim
124317017Sdimpublic:
125317017Sdim  /// Takes in a reference to a FuncIdHelper in order to have ready access to
126317017Sdim  /// Symbol names.
127317017Sdim  explicit GraphRenderer(const FuncIdConversionHelper &FuncIdHelper, bool DSC)
128317017Sdim      : FuncIdHelper(FuncIdHelper), DeduceSiblingCalls(DSC),
129317017Sdim        CHelper(ColorHelper::SequentialScheme::OrRd) {
130317017Sdim    G[0] = {};
131317017Sdim  }
132317017Sdim
133317017Sdim  /// Process an Xray record and expand the graph.
134317017Sdim  ///
135317017Sdim  /// This Function will return true on success, or false if records are not
136317017Sdim  /// presented in per-thread call-tree DFS order. (That is for each thread the
137317017Sdim  /// Records should be in order runtime on an ideal system.)
138317017Sdim  ///
139317017Sdim  /// FIXME: Make this more robust against small irregularities.
140317017Sdim  Error accountRecord(const XRayRecord &Record);
141317017Sdim
142317017Sdim  const PerThreadFunctionStackMap &getPerThreadFunctionStack() const {
143317017Sdim    return PerThreadFunctionStack;
144317017Sdim  }
145317017Sdim
146317017Sdim  /// Output the Embedded graph in DOT format on \p OS, labeling the edges by
147317017Sdim  /// \p T
148317017Sdim  void exportGraphAsDOT(raw_ostream &OS, const XRayFileHeader &H,
149317017Sdim                        StatType EdgeLabel = StatType::NONE,
150317017Sdim                        StatType EdgeColor = StatType::NONE,
151317017Sdim                        StatType VertexLabel = StatType::NONE,
152317017Sdim                        StatType VertexColor = StatType::NONE);
153317017Sdim
154317017Sdim  /// Get a reference to the internal graph.
155317017Sdim  const GraphT &getGraph() {
156317017Sdim    calculateEdgeStatistics();
157317017Sdim    calculateVertexStatistics();
158317017Sdim    return G;
159317017Sdim  }
160317017Sdim};
161317017Sdim}
162317017Sdim}
163317017Sdim
164317017Sdim#endif // XRAY_GRAPH_H
165