diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-04-26 19:45:00 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-04-26 19:45:00 +0000 |
commit | 12f3ca4cdb95b193af905a00e722a4dcb40b3de3 (patch) | |
tree | ae1a7fcfc24a8d4b23206c57121c3f361d4b7f84 /tools/llvm-xray/xray-graph.cc | |
parent | d99dafe2e4a385dd2a6c76da6d8258deb100657b (diff) | |
download | src-12f3ca4cdb95b193af905a00e722a4dcb40b3de3.tar.gz src-12f3ca4cdb95b193af905a00e722a4dcb40b3de3.zip |
Vendor import of llvm trunk r301441:vendor/llvm/llvm-trunk-r301441
Notes
Notes:
svn path=/vendor/llvm/dist/; revision=317461
svn path=/vendor/llvm/llvm-trunk-r301441/; revision=317462; tag=vendor/llvm/llvm-trunk-r301441
Diffstat (limited to 'tools/llvm-xray/xray-graph.cc')
-rw-r--r-- | tools/llvm-xray/xray-graph.cc | 196 |
1 files changed, 94 insertions, 102 deletions
diff --git a/tools/llvm-xray/xray-graph.cc b/tools/llvm-xray/xray-graph.cc index 9be0b70c2cdd..685c24cb9187 100644 --- a/tools/llvm-xray/xray-graph.cc +++ b/tools/llvm-xray/xray-graph.cc @@ -19,7 +19,6 @@ #include "xray-graph.h" #include "xray-registry.h" -#include "llvm/ADT/ArrayRef.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/XRay/InstrumentationMap.h" @@ -98,7 +97,7 @@ static cl::opt<GraphRenderer::StatType> GraphVertexLabel( cl::value_desc("field"), cl::sub(GraphC), cl::init(GraphRenderer::StatType::NONE), cl::values(clEnumValN(GraphRenderer::StatType::NONE, "none", - "Do not label Edges"), + "Do not label Vertices"), clEnumValN(GraphRenderer::StatType::COUNT, "count", "function call counts"), clEnumValN(GraphRenderer::StatType::MIN, "min", @@ -123,7 +122,7 @@ static cl::opt<GraphRenderer::StatType> GraphEdgeColorType( cl::value_desc("field"), cl::sub(GraphC), cl::init(GraphRenderer::StatType::NONE), cl::values(clEnumValN(GraphRenderer::StatType::NONE, "none", - "Do not label Edges"), + "Do not color Edges"), clEnumValN(GraphRenderer::StatType::COUNT, "count", "function call counts"), clEnumValN(GraphRenderer::StatType::MIN, "min", @@ -148,7 +147,7 @@ static cl::opt<GraphRenderer::StatType> GraphVertexColorType( cl::value_desc("field"), cl::sub(GraphC), cl::init(GraphRenderer::StatType::NONE), cl::values(clEnumValN(GraphRenderer::StatType::NONE, "none", - "Do not label Edges"), + "Do not color vertices"), clEnumValN(GraphRenderer::StatType::COUNT, "count", "function call counts"), clEnumValN(GraphRenderer::StatType::MIN, "min", @@ -210,7 +209,7 @@ Error GraphRenderer::accountRecord(const XRayRecord &Record) { auto &ThreadStack = PerThreadFunctionStack[Record.TId]; switch (Record.Type) { case RecordTypes::ENTER: { - if (G.count(Record.FuncId) == 0) + if (Record.FuncId != 0 && G.count(Record.FuncId) == 0) G[Record.FuncId].SymbolName = FuncIdHelper.SymbolOrNumber(Record.FuncId); ThreadStack.push_back({Record.FuncId, Record.TSC}); break; @@ -312,12 +311,9 @@ void GraphRenderer::calculateVertexStatistics() { // TimeStat element. static void normalizeTimeStat(GraphRenderer::TimeStat &S, double CycleFrequency) { - S.Min /= CycleFrequency; - S.Median /= CycleFrequency; - S.Max /= CycleFrequency; - S.Sum /= CycleFrequency; - S.Pct90 /= CycleFrequency; - S.Pct99 /= CycleFrequency; + int64_t OldCount = S.Count; + S = S / CycleFrequency; + S.Count = OldCount; } // Normalises the statistics in the graph for a given TSC frequency. @@ -337,32 +333,22 @@ void GraphRenderer::normalizeStatistics(double CycleFrequency) { // Returns a string containing the value of statistic field T std::string -GraphRenderer::TimeStat::getAsString(GraphRenderer::StatType T) const { +GraphRenderer::TimeStat::getString(GraphRenderer::StatType T) const { std::string St; raw_string_ostream S{St}; + double TimeStat::*DoubleStatPtrs[] = {&TimeStat::Min, &TimeStat::Median, + &TimeStat::Pct90, &TimeStat::Pct99, + &TimeStat::Max, &TimeStat::Sum}; switch (T) { + case GraphRenderer::StatType::NONE: + break; case GraphRenderer::StatType::COUNT: S << Count; break; - case GraphRenderer::StatType::MIN: - S << Min; - break; - case GraphRenderer::StatType::MED: - S << Median; - break; - case GraphRenderer::StatType::PCT90: - S << Pct90; - break; - case GraphRenderer::StatType::PCT99: - S << Pct99; - break; - case GraphRenderer::StatType::MAX: - S << Max; - break; - case GraphRenderer::StatType::SUM: - S << Sum; - break; - case GraphRenderer::StatType::NONE: + default: + S << (*this).* + DoubleStatPtrs[static_cast<int>(T) - + static_cast<int>(GraphRenderer::StatType::MIN)]; break; } return S.str(); @@ -370,38 +356,25 @@ GraphRenderer::TimeStat::getAsString(GraphRenderer::StatType T) const { // Returns the quotient between the property T of this and another TimeStat as // a double -double GraphRenderer::TimeStat::compare(StatType T, const TimeStat &O) const { +double GraphRenderer::TimeStat::getDouble(StatType T) const { double retval = 0; + double TimeStat::*DoubleStatPtrs[] = {&TimeStat::Min, &TimeStat::Median, + &TimeStat::Pct90, &TimeStat::Pct99, + &TimeStat::Max, &TimeStat::Sum}; switch (T) { - case GraphRenderer::StatType::COUNT: - retval = static_cast<double>(Count) / static_cast<double>(O.Count); - break; - case GraphRenderer::StatType::MIN: - retval = Min / O.Min; - break; - case GraphRenderer::StatType::MED: - retval = Median / O.Median; - break; - case GraphRenderer::StatType::PCT90: - retval = Pct90 / O.Pct90; - break; - case GraphRenderer::StatType::PCT99: - retval = Pct99 / O.Pct99; - break; - case GraphRenderer::StatType::MAX: - retval = Max / O.Max; - break; - case GraphRenderer::StatType::SUM: - retval = Sum / O.Sum; - break; case GraphRenderer::StatType::NONE: retval = 0.0; break; + case GraphRenderer::StatType::COUNT: + retval = static_cast<double>(Count); + break; + default: + retval = + (*this).*DoubleStatPtrs[static_cast<int>(T) - + static_cast<int>(GraphRenderer::StatType::MIN)]; + break; } - return std::sqrt( - retval); // the square root here provides more dynamic contrast for - // low runtime edges, giving better separation and - // coloring lower down the call stack. + return retval; } // Outputs a DOT format version of the Graph embedded in the GraphRenderer @@ -410,17 +383,8 @@ double GraphRenderer::TimeStat::compare(StatType T, const TimeStat &O) const { // annotations. // // FIXME: output more information, better presented. -void GraphRenderer::exportGraphAsDOT(raw_ostream &OS, const XRayFileHeader &H, - StatType ET, StatType EC, StatType VT, - StatType VC) { - G.GraphEdgeMax = {}; - G.GraphVertexMax = {}; - calculateEdgeStatistics(); - calculateVertexStatistics(); - - if (H.CycleFrequency) - normalizeStatistics(H.CycleFrequency); - +void GraphRenderer::exportGraphAsDOT(raw_ostream &OS, StatType ET, StatType EC, + StatType VT, StatType VC) { OS << "digraph xray {\n"; if (VT != StatType::NONE) @@ -429,9 +393,11 @@ void GraphRenderer::exportGraphAsDOT(raw_ostream &OS, const XRayFileHeader &H, for (const auto &E : G.edges()) { const auto &S = E.second.S; OS << "F" << E.first.first << " -> " - << "F" << E.first.second << " [label=\"" << S.getAsString(ET) << "\""; + << "F" << E.first.second << " [label=\"" << S.getString(ET) << "\""; if (EC != StatType::NONE) - OS << " color=\"" << CHelper.getColorString(S.compare(EC, G.GraphEdgeMax)) + OS << " color=\"" + << CHelper.getColorString( + std::sqrt(S.getDouble(EC) / G.GraphEdgeMax.getDouble(EC))) << "\""; OS << "];\n"; } @@ -444,26 +410,20 @@ void GraphRenderer::exportGraphAsDOT(raw_ostream &OS, const XRayFileHeader &H, << (VA.SymbolName.size() > 40 ? VA.SymbolName.substr(0, 40) + "..." : VA.SymbolName); if (VT != StatType::NONE) - OS << "|" << VA.S.getAsString(VT) << "}\""; + OS << "|" << VA.S.getString(VT) << "}\""; else OS << "\""; if (VC != StatType::NONE) - OS << " color=\"" << CHelper.getColorString(VA.S.compare(VC, G.GraphVertexMax)) + OS << " color=\"" + << CHelper.getColorString( + std::sqrt(VA.S.getDouble(VC) / G.GraphVertexMax.getDouble(VC))) << "\""; OS << "];\n"; } OS << "}\n"; } -// Here we register and implement the llvm-xray graph subcommand. -// The bulk of this code reads in the options, opens the required files, uses -// those files to create a context for analysing the xray trace, then there is a -// short loop which actually analyses the trace, generates the graph and then -// outputs it as a DOT. -// -// FIXME: include additional filtering and annalysis passes to provide more -// specific useful information. -static CommandRegistration Unused(&GraphC, []() -> Error { +Expected<GraphRenderer> GraphRenderer::Factory::getGraphRenderer() { InstrumentationMap Map; if (!GraphInstrMap.empty()) { auto InstrumentationMapOrError = loadInstrumentationMap(GraphInstrMap); @@ -477,30 +437,16 @@ static CommandRegistration Unused(&GraphC, []() -> Error { } const auto &FunctionAddresses = Map.getFunctionAddresses(); + symbolize::LLVMSymbolizer::Options Opts( symbolize::FunctionNameKind::LinkageName, true, true, false, ""); symbolize::LLVMSymbolizer Symbolizer(Opts); - llvm::xray::FuncIdConversionHelper FuncIdHelper(GraphInstrMap, Symbolizer, - FunctionAddresses); - xray::GraphRenderer GR(FuncIdHelper, GraphDeduceSiblingCalls); - std::error_code EC; - raw_fd_ostream OS(GraphOutput, EC, sys::fs::OpenFlags::F_Text); - if (EC) - return make_error<StringError>( - Twine("Cannot open file '") + GraphOutput + "' for writing.", EC); - - auto TraceOrErr = loadTraceFile(GraphInput, true); - if (!TraceOrErr) - return joinErrors( - make_error<StringError>(Twine("Failed loading input file '") + - GraphInput + "'", - make_error_code(llvm::errc::invalid_argument)), - TraceOrErr.takeError()); - - auto &Trace = *TraceOrErr; const auto &Header = Trace.getFileHeader(); - // Here we generate the call graph from entries we find in the trace. + llvm::xray::FuncIdConversionHelper FuncIdHelper(InstrMap, Symbolizer, + FunctionAddresses); + + xray::GraphRenderer GR(FuncIdHelper, DeduceSiblingCalls); for (const auto &Record : Trace) { auto E = GR.accountRecord(Record); if (!E) @@ -523,7 +469,53 @@ static CommandRegistration Unused(&GraphC, []() -> Error { handleAllErrors(std::move(E), [&](const ErrorInfoBase &E) { E.log(errs()); }); } - GR.exportGraphAsDOT(OS, Header, GraphEdgeLabel, GraphEdgeColorType, - GraphVertexLabel, GraphVertexColorType); + + GR.G.GraphEdgeMax = {}; + GR.G.GraphVertexMax = {}; + GR.calculateEdgeStatistics(); + GR.calculateVertexStatistics(); + + if (Header.CycleFrequency) + GR.normalizeStatistics(Header.CycleFrequency); + + return GR; +} + +// Here we register and implement the llvm-xray graph subcommand. +// The bulk of this code reads in the options, opens the required files, uses +// those files to create a context for analysing the xray trace, then there is a +// short loop which actually analyses the trace, generates the graph and then +// outputs it as a DOT. +// +// FIXME: include additional filtering and annalysis passes to provide more +// specific useful information. +static CommandRegistration Unused(&GraphC, []() -> Error { + GraphRenderer::Factory F; + + F.KeepGoing = GraphKeepGoing; + F.DeduceSiblingCalls = GraphDeduceSiblingCalls; + F.InstrMap = GraphInstrMap; + + auto TraceOrErr = loadTraceFile(GraphInput, true); + + if (!TraceOrErr) + return make_error<StringError>( + Twine("Failed loading input file '") + GraphInput + "'", + make_error_code(llvm::errc::invalid_argument)); + + F.Trace = std::move(*TraceOrErr); + auto GROrError = F.getGraphRenderer(); + if (!GROrError) + return GROrError.takeError(); + auto &GR = *GROrError; + + std::error_code EC; + raw_fd_ostream OS(GraphOutput, EC, sys::fs::OpenFlags::F_Text); + if (EC) + return make_error<StringError>( + Twine("Cannot open file '") + GraphOutput + "' for writing.", EC); + + GR.exportGraphAsDOT(OS, GraphEdgeLabel, GraphEdgeColorType, GraphVertexLabel, + GraphVertexColorType); return Error::success(); }); |