diff options
Diffstat (limited to 'llvm/tools/llvm-xray/xray-graph.h')
| -rw-r--r-- | llvm/tools/llvm-xray/xray-graph.h | 231 |
1 files changed, 231 insertions, 0 deletions
diff --git a/llvm/tools/llvm-xray/xray-graph.h b/llvm/tools/llvm-xray/xray-graph.h new file mode 100644 index 000000000000..23372d40f05e --- /dev/null +++ b/llvm/tools/llvm-xray/xray-graph.h @@ -0,0 +1,231 @@ +//===-- xray-graph.h - XRay Function Call Graph Renderer --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Generate a DOT file to represent the function call graph encountered in +// the trace. +// +//===----------------------------------------------------------------------===// + +#ifndef XRAY_GRAPH_H +#define XRAY_GRAPH_H + +#include <string> +#include <vector> + +#include "func-id-helper.h" +#include "xray-color-helper.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/Program.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/XRay/Graph.h" +#include "llvm/XRay/Trace.h" +#include "llvm/XRay/XRayRecord.h" + +namespace llvm { +namespace xray { + +/// A class encapsulating the logic related to analyzing XRay traces, producting +/// Graphs from them and then exporting those graphs for review. +class GraphRenderer { +public: + /// An enum for enumerating the various statistics gathered on latencies + enum class StatType { NONE, COUNT, MIN, MED, PCT90, PCT99, MAX, SUM }; + + /// An inner struct for common timing statistics information + struct TimeStat { + int64_t Count; + double Min; + double Median; + double Pct90; + double Pct99; + double Max; + double Sum; + + std::string getString(StatType T) const; + double getDouble(StatType T) const; + }; + using TimestampT = uint64_t; + + /// An inner struct for storing edge attributes for our graph. Here the + /// attributes are mainly function call statistics. + /// + /// FIXME: expand to contain more information eg call latencies. + struct CallStats { + TimeStat S; + std::vector<TimestampT> Timings; + }; + + /// An Inner Struct for storing vertex attributes, at the moment just + /// SymbolNames, however in future we could store bulk function statistics. + /// + /// FIXME: Store more attributes based on instrumentation map. + struct FunctionStats { + std::string SymbolName; + TimeStat S = {}; + }; + + struct FunctionAttr { + int32_t FuncId; + uint64_t TSC; + }; + + using FunctionStack = SmallVector<FunctionAttr, 4>; + + using PerThreadFunctionStackMap = DenseMap<uint32_t, FunctionStack>; + + class GraphT : public Graph<FunctionStats, CallStats, int32_t> { + public: + TimeStat GraphEdgeMax = {}; + TimeStat GraphVertexMax = {}; + }; + + GraphT G; + using VertexIdentifier = typename decltype(G)::VertexIdentifier; + using EdgeIdentifier = decltype(G)::EdgeIdentifier; + + /// Use a Map to store the Function stack for each thread whilst building the + /// graph. + /// + /// FIXME: Perhaps we can Build this into LatencyAccountant? or vise versa? + PerThreadFunctionStackMap PerThreadFunctionStack; + + /// Usefull object for getting human readable Symbol Names. + FuncIdConversionHelper FuncIdHelper; + bool DeduceSiblingCalls = false; + TimestampT CurrentMaxTSC = 0; + + /// A private function to help implement the statistic generation functions; + template <typename U> + void getStats(U begin, U end, GraphRenderer::TimeStat &S); + void updateMaxStats(const TimeStat &S, TimeStat &M); + + /// Calculates latency statistics for each edge and stores the data in the + /// Graph + void calculateEdgeStatistics(); + + /// Calculates latency statistics for each vertex and stores the data in the + /// Graph + void calculateVertexStatistics(); + + /// Normalises latency statistics for each edge and vertex by CycleFrequency; + void normalizeStatistics(double CycleFrequency); + + /// An object to color gradients + ColorHelper CHelper; + +public: + /// Takes in a reference to a FuncIdHelper in order to have ready access to + /// Symbol names. + explicit GraphRenderer(const FuncIdConversionHelper &FuncIdHelper, bool DSC) + : FuncIdHelper(FuncIdHelper), DeduceSiblingCalls(DSC), + CHelper(ColorHelper::SequentialScheme::OrRd) { + G[0] = {}; + } + + /// Process an Xray record and expand the graph. + /// + /// This Function will return true on success, or false if records are not + /// presented in per-thread call-tree DFS order. (That is for each thread the + /// Records should be in order runtime on an ideal system.) + /// + /// FIXME: Make this more robust against small irregularities. + Error accountRecord(const XRayRecord &Record); + + const PerThreadFunctionStackMap &getPerThreadFunctionStack() const { + return PerThreadFunctionStack; + } + + class Factory { + public: + bool KeepGoing; + bool DeduceSiblingCalls; + std::string InstrMap; + ::llvm::xray::Trace Trace; + Expected<GraphRenderer> getGraphRenderer(); + }; + + /// Output the Embedded graph in DOT format on \p OS, labeling the edges by + /// \p T + void exportGraphAsDOT(raw_ostream &OS, StatType EdgeLabel = StatType::NONE, + StatType EdgeColor = StatType::NONE, + StatType VertexLabel = StatType::NONE, + StatType VertexColor = StatType::NONE); + + /// Get a reference to the internal graph. + const GraphT &getGraph() { return G; } +}; + +/// Vector Sum of TimeStats +inline GraphRenderer::TimeStat operator+(const GraphRenderer::TimeStat &A, + const GraphRenderer::TimeStat &B) { + return {A.Count + B.Count, A.Min + B.Min, A.Median + B.Median, + A.Pct90 + B.Pct90, A.Pct99 + B.Pct99, A.Max + B.Max, + A.Sum + B.Sum}; +} + +/// Vector Difference of Timestats +inline GraphRenderer::TimeStat operator-(const GraphRenderer::TimeStat &A, + const GraphRenderer::TimeStat &B) { + + return {A.Count - B.Count, A.Min - B.Min, A.Median - B.Median, + A.Pct90 - B.Pct90, A.Pct99 - B.Pct99, A.Max - B.Max, + A.Sum - B.Sum}; +} + +/// Scalar Diference of TimeStat and double +inline GraphRenderer::TimeStat operator/(const GraphRenderer::TimeStat &A, + double B) { + + return {static_cast<int64_t>(A.Count / B), + A.Min / B, + A.Median / B, + A.Pct90 / B, + A.Pct99 / B, + A.Max / B, + A.Sum / B}; +} + +/// Scalar product of TimeStat and Double +inline GraphRenderer::TimeStat operator*(const GraphRenderer::TimeStat &A, + double B) { + return {static_cast<int64_t>(A.Count * B), + A.Min * B, + A.Median * B, + A.Pct90 * B, + A.Pct99 * B, + A.Max * B, + A.Sum * B}; +} + +/// Scalar product of double TimeStat +inline GraphRenderer::TimeStat operator*(double A, + const GraphRenderer::TimeStat &B) { + return B * A; +} + +/// Hadamard Product of TimeStats +inline GraphRenderer::TimeStat operator*(const GraphRenderer::TimeStat &A, + const GraphRenderer::TimeStat &B) { + return {A.Count * B.Count, A.Min * B.Min, A.Median * B.Median, + A.Pct90 * B.Pct90, A.Pct99 * B.Pct99, A.Max * B.Max, + A.Sum * B.Sum}; +} + +/// Hadamard Division of TimeStats +inline GraphRenderer::TimeStat operator/(const GraphRenderer::TimeStat &A, + const GraphRenderer::TimeStat &B) { + return {A.Count / B.Count, A.Min / B.Min, A.Median / B.Median, + A.Pct90 / B.Pct90, A.Pct99 / B.Pct99, A.Max / B.Max, + A.Sum / B.Sum}; +} +} // namespace xray +} // namespace llvm + +#endif // XRAY_GRAPH_H |
