#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 {
class GraphRenderer {
public:
enum class StatType { NONE, COUNT, MIN, MED, PCT90, PCT99, MAX, SUM };
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;
struct CallStats {
TimeStat S;
std::vector<TimestampT> Timings;
};
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;
PerThreadFunctionStackMap PerThreadFunctionStack;
FuncIdConversionHelper FuncIdHelper;
bool DeduceSiblingCalls = false;
TimestampT CurrentMaxTSC = 0;
template <typename U>
void getStats(U begin, U end, GraphRenderer::TimeStat &S);
void updateMaxStats(const TimeStat &S, TimeStat &M);
void calculateEdgeStatistics();
void calculateVertexStatistics();
void normalizeStatistics(double CycleFrequency);
ColorHelper CHelper;
public:
explicit GraphRenderer(const FuncIdConversionHelper &FuncIdHelper, bool DSC)
: FuncIdHelper(FuncIdHelper), DeduceSiblingCalls(DSC),
CHelper(ColorHelper::SequentialScheme::OrRd) {
G[0] = {};
}
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();
};
void exportGraphAsDOT(raw_ostream &OS, StatType EdgeLabel = StatType::NONE,
StatType EdgeColor = StatType::NONE,
StatType VertexLabel = StatType::NONE,
StatType VertexColor = StatType::NONE);
const GraphT &getGraph() { return G; }
};
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};
}
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};
}
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};
}
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};
}
inline GraphRenderer::TimeStat operator*(double A,
const GraphRenderer::TimeStat &B) {
return B * A;
}
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};
}
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};
}
} }
#endif