Changeset View
Changeset View
Standalone View
Standalone View
tools/llvm-xray/xray-graph.h
Show All 18 Lines | |||||
#include <vector> | #include <vector> | ||||
#include "func-id-helper.h" | #include "func-id-helper.h" | ||||
#include "llvm/ADT/DenseMap.h" | #include "llvm/ADT/DenseMap.h" | ||||
#include "llvm/ADT/SmallVector.h" | #include "llvm/ADT/SmallVector.h" | ||||
#include "llvm/Support/Errc.h" | #include "llvm/Support/Errc.h" | ||||
#include "llvm/Support/Program.h" | #include "llvm/Support/Program.h" | ||||
#include "llvm/Support/raw_ostream.h" | #include "llvm/Support/raw_ostream.h" | ||||
#include "llvm/XRay/Graph.h" | |||||
#include "llvm/XRay/Trace.h" | #include "llvm/XRay/Trace.h" | ||||
#include "llvm/XRay/XRayRecord.h" | #include "llvm/XRay/XRayRecord.h" | ||||
namespace llvm { | namespace llvm { | ||||
namespace xray { | namespace xray { | ||||
/// A class encapsulating the logic related to analyzing XRay traces, producting | /// A class encapsulating the logic related to analyzing XRay traces, producting | ||||
/// Graphs from them and then exporting those graphs for review. | /// Graphs from them and then exporting those graphs for review. | ||||
Show All 9 Lines | struct TimeStat { | ||||
double Median = 0; | double Median = 0; | ||||
double Pct90 = 0; | double Pct90 = 0; | ||||
double Pct99 = 0; | double Pct99 = 0; | ||||
double Max = 0; | double Max = 0; | ||||
double Sum = 0; | double Sum = 0; | ||||
std::string getAsString(StatType T) const; | std::string getAsString(StatType T) const; | ||||
double compare(StatType T, const TimeStat &Other) const; | double compare(StatType T, const TimeStat &Other) const; | ||||
}; | }; | ||||
typedef uint64_t TimestampT; | |||||
/// An inner struct for storing edge attributes for our graph. Here the | /// An inner struct for storing edge attributes for our graph. Here the | ||||
/// attributes are mainly function call statistics. | /// attributes are mainly function call statistics. | ||||
/// | /// | ||||
/// FIXME: expand to contain more information eg call latencies. | /// FIXME: expand to contain more information eg call latencies. | ||||
struct EdgeAttribute { | struct EdgeAttribute { | ||||
TimeStat S; | TimeStat S; | ||||
std::vector<uint64_t> Timings; | std::vector<TimestampT> Timings; | ||||
}; | }; | ||||
/// An Inner Struct for storing vertex attributes, at the moment just | /// An Inner Struct for storing vertex attributes, at the moment just | ||||
/// SymbolNames, however in future we could store bulk function statistics. | /// SymbolNames, however in future we could store bulk function statistics. | ||||
/// | /// | ||||
/// FIXME: Store more attributes based on instrumentation map. | /// FIXME: Store more attributes based on instrumentation map. | ||||
struct VertexAttribute { | struct VertexAttribute { | ||||
std::string SymbolName; | std::string SymbolName; | ||||
TimeStat S; | TimeStat S; | ||||
}; | }; | ||||
struct FunctionAttr { | struct FunctionAttr { | ||||
int32_t FuncId; | int32_t FuncId; | ||||
uint64_t TSC; | uint64_t TSC; | ||||
}; | }; | ||||
typedef SmallVector<FunctionAttr, 4> FunctionStack; | typedef SmallVector<FunctionAttr, 4> FunctionStack; | ||||
typedef DenseMap<llvm::sys::ProcessInfo::ProcessId, FunctionStack> | typedef DenseMap<llvm::sys::ProcessInfo::ProcessId, FunctionStack> | ||||
PerThreadFunctionStackMap; | PerThreadFunctionStackMap; | ||||
private: | class GraphT : public Graph<VertexAttribute, EdgeAttribute, int32_t> { | ||||
/// The Graph stored in an edge-list like format, with the edges also having | public: | ||||
/// An attached set of attributes. | TimeStat GraphEdgeMax = {}; | ||||
DenseMap<int32_t, DenseMap<int32_t, EdgeAttribute>> Graph; | TimeStat GraphVertexMax = {}; | ||||
}; | |||||
/// Graph Vertex Attributes. These are presently stored seperate from the | |||||
/// main graph. | |||||
DenseMap<int32_t, VertexAttribute> VertexAttrs; | |||||
TimeStat GraphEdgeMax; | GraphT G; | ||||
TimeStat GraphVertexMax; | typedef typename decltype(G)::VertexIdentifier VertexIdentifier; | ||||
typedef typename decltype(G)::EdgeIdentifier EdgeIdentifier; | |||||
dberris: Consider using better names than generic terms like `VertexAttribute` -- in the context of XRay… | |||||
/// Use a Map to store the Function stack for each thread whilst building the | /// Use a Map to store the Function stack for each thread whilst building the | ||||
/// graph. | /// graph. | ||||
/// | /// | ||||
/// FIXME: Perhaps we can Build this into LatencyAccountant? or vise versa? | /// FIXME: Perhaps we can Build this into LatencyAccountant? or vise versa? | ||||
PerThreadFunctionStackMap PerThreadFunctionStack; | PerThreadFunctionStackMap PerThreadFunctionStack; | ||||
/// Usefull object for getting human readable Symbol Names. | /// Usefull object for getting human readable Symbol Names. | ||||
FuncIdConversionHelper &FuncIdHelper; | FuncIdConversionHelper &FuncIdHelper; | ||||
bool DeduceSiblingCalls = false; | bool DeduceSiblingCalls = false; | ||||
uint64_t CurrentMaxTSC = 0; | TimestampT CurrentMaxTSC = 0; | ||||
/// A private function to help implement the statistic generation functions; | /// A private function to help implement the statistic generation functions; | ||||
template <typename U> | template <typename U> | ||||
void getStats(U begin, U end, GraphRenderer::TimeStat &S); | void getStats(U begin, U end, GraphRenderer::TimeStat &S); | ||||
void updateMaxStats(const TimeStat &S, TimeStat &M); | void updateMaxStats(const TimeStat &S, TimeStat &M); | ||||
/// Calculates latency statistics for each edge and stores the data in the | /// Calculates latency statistics for each edge and stores the data in the | ||||
/// Graph | /// Graph | ||||
void calculateEdgeStatistics(); | void calculateEdgeStatistics(); | ||||
/// Calculates latency statistics for each vertex and stores the data in the | /// Calculates latency statistics for each vertex and stores the data in the | ||||
/// Graph | /// Graph | ||||
void calculateVertexStatistics(); | void calculateVertexStatistics(); | ||||
/// Normalises latency statistics for each edge and vertex by CycleFrequency; | /// Normalises latency statistics for each edge and vertex by CycleFrequency; | ||||
void normalizeStatistics(double CycleFrequency); | void normalizeStatistics(double CycleFrequency); | ||||
public: | public: | ||||
/// Takes in a reference to a FuncIdHelper in order to have ready access to | /// Takes in a reference to a FuncIdHelper in order to have ready access to | ||||
/// Symbol names. | /// Symbol names. | ||||
explicit GraphRenderer(FuncIdConversionHelper &FuncIdHelper, bool DSC) | explicit GraphRenderer(FuncIdConversionHelper &FuncIdHelper, bool DSC) | ||||
: FuncIdHelper(FuncIdHelper), DeduceSiblingCalls(DSC) {} | : FuncIdHelper(FuncIdHelper), DeduceSiblingCalls(DSC) { | ||||
G[0] = {}; | |||||
Probably not for now, but it would be great if we can construct a graph with a terse interface. Something like: Graph<int, int, int> G( {1, 2, 3, 4, 5}, {{1, 2}, {2, 3}, {3, 4}}); Maybe write as a TODO on the Graph type? dberris: Probably not for now, but it would be great if we can construct a graph with a terse interface. | |||||
} | |||||
/// Process an Xray record and expand the graph. | /// Process an Xray record and expand the graph. | ||||
/// | /// | ||||
/// This Function will return true on success, or false if records are not | /// 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 | /// presented in per-thread call-tree DFS order. (That is for each thread the | ||||
/// Records should be in order runtime on an ideal system.) | /// Records should be in order runtime on an ideal system.) | ||||
/// | /// | ||||
/// FIXME: Make this more robust against small irregularities. | /// FIXME: Make this more robust against small irregularities. | ||||
Error accountRecord(const XRayRecord &Record); | Error accountRecord(const XRayRecord &Record); | ||||
const PerThreadFunctionStackMap getPerThreadFunctionStack() const { | const PerThreadFunctionStackMap &getPerThreadFunctionStack() const { | ||||
return PerThreadFunctionStack; | return PerThreadFunctionStack; | ||||
} | } | ||||
/// Output the Embedded graph in DOT format on \p OS, labeling the edges by | /// Output the Embedded graph in DOT format on \p OS, labeling the edges by | ||||
/// \p T | /// \p T | ||||
void exportGraphAsDOT(raw_ostream &OS, const XRayFileHeader &H, | void exportGraphAsDOT(raw_ostream &OS, const XRayFileHeader &H, | ||||
StatType EdgeLabel = StatType::NONE, | StatType EdgeLabel = StatType::NONE, | ||||
StatType EdgeColor = StatType::NONE, | StatType EdgeColor = StatType::NONE, | ||||
StatType VertexLabel = StatType::NONE, | StatType VertexLabel = StatType::NONE, | ||||
StatType VertexColor = StatType::NONE); | StatType VertexColor = StatType::NONE); | ||||
/// Get a reference to the internal graph. | |||||
Empty line before? dberris: Empty line before? | |||||
const GraphT &getGraph() { | |||||
calculateEdgeStatistics(); | |||||
calculateVertexStatistics(); | |||||
return G; | |||||
} | |||||
}; | }; | ||||
} | } | ||||
} | } | ||||
#endif // XRAY_GRAPH_H | #endif // XRAY_GRAPH_H |
Consider using better names than generic terms like VertexAttribute -- in the context of XRay this might be FunctionStats, and EdgeAttribute might better be CallStats.