summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVedant Kumar <vsk@apple.com>2018-07-24 00:41:29 +0000
committerVedant Kumar <vsk@apple.com>2018-07-24 00:41:29 +0000
commitd6ff43cc71acde958d3927952a049f72e88fd79f (patch)
treeb7b43eb3873f317e98dca3c12ad4a0c6c5e60a60
parentca407c43364e4315f8ae32bd0c0e70c5aafb7962 (diff)
downloadbcm5719-llvm-d6ff43cc71acde958d3927952a049f72e88fd79f.tar.gz
bcm5719-llvm-d6ff43cc71acde958d3927952a049f72e88fd79f.zip
[Debugify] Export per-pass debug info loss statistics
Add a -debugify-export option to opt. This exports per-pass `debugify` loss statistics to a file in CSV format. For some interesting numbers on debug value loss during an -O2 build of the sqlite3 amalgamation, see the review thread. Differential Revision: https://reviews.llvm.org/D49003 llvm-svn: 337787
-rw-r--r--llvm/test/DebugInfo/debugify-export.ll14
-rw-r--r--llvm/tools/opt/Debugify.cpp67
-rw-r--r--llvm/tools/opt/Debugify.h40
-rw-r--r--llvm/tools/opt/opt.cpp23
4 files changed, 128 insertions, 16 deletions
diff --git a/llvm/test/DebugInfo/debugify-export.ll b/llvm/test/DebugInfo/debugify-export.ll
new file mode 100644
index 00000000000..77930355ae9
--- /dev/null
+++ b/llvm/test/DebugInfo/debugify-export.ll
@@ -0,0 +1,14 @@
+; RUN: opt < %s -debugify-each -debugify-quiet -debugify-export - -o /dev/null | FileCheck %s
+
+; CHECK: Pass Name
+; CHECK-SAME: # of missing debug values
+; CHECK-SAME: # of missing locations
+; CHECK-SAME: Missing/Expected value ratio
+; CHECK-SAME: Missing/Expected location ratio
+
+; CHECK: Module Verifier
+; CHECK-SAME: 0,0,0.000000e+00,0.000000e+00
+
+define void @foo() {
+ ret void
+}
diff --git a/llvm/tools/opt/Debugify.cpp b/llvm/tools/opt/Debugify.cpp
index b56a94b6e5f..6c3cdc75e33 100644
--- a/llvm/tools/opt/Debugify.cpp
+++ b/llvm/tools/opt/Debugify.cpp
@@ -209,7 +209,7 @@ bool diagnoseMisSizedDbgValue(Module &M, DbgValueInst *DVI) {
bool checkDebugifyMetadata(Module &M,
iterator_range<Module::iterator> Functions,
StringRef NameOfWrappedPass, StringRef Banner,
- bool Strip) {
+ bool Strip, DebugifyStatsMap *StatsMap) {
// Skip modules without debugify metadata.
NamedMDNode *NMD = M.getNamedMetadata("llvm.debugify");
if (!NMD) {
@@ -227,6 +227,11 @@ bool checkDebugifyMetadata(Module &M,
unsigned OriginalNumVars = getDebugifyOperand(1);
bool HasErrors = false;
+ // Track debug info loss statistics if able.
+ DebugifyStatistics *Stats = nullptr;
+ if (StatsMap && !NameOfWrappedPass.empty())
+ Stats = &StatsMap->operator[](NameOfWrappedPass);
+
BitVector MissingLines{OriginalNumLines, true};
BitVector MissingVars{OriginalNumVars, true};
for (Function &F : Functions) {
@@ -276,6 +281,14 @@ bool checkDebugifyMetadata(Module &M,
for (unsigned Idx : MissingVars.set_bits())
dbg() << "WARNING: Missing variable " << Idx + 1 << "\n";
+ // Update DI loss statistics.
+ if (Stats) {
+ Stats->NumDbgLocsExpected += OriginalNumLines;
+ Stats->NumDbgLocsMissing += MissingLines.count();
+ Stats->NumDbgValuesExpected += OriginalNumVars;
+ Stats->NumDbgValuesMissing += MissingVars.count();
+ }
+
dbg() << Banner;
if (!NameOfWrappedPass.empty())
dbg() << " [" << NameOfWrappedPass << "]";
@@ -331,11 +344,13 @@ struct DebugifyFunctionPass : public FunctionPass {
struct CheckDebugifyModulePass : public ModulePass {
bool runOnModule(Module &M) override {
return checkDebugifyMetadata(M, M.functions(), NameOfWrappedPass,
- "CheckModuleDebugify", Strip);
+ "CheckModuleDebugify", Strip, StatsMap);
}
- CheckDebugifyModulePass(bool Strip = false, StringRef NameOfWrappedPass = "")
- : ModulePass(ID), Strip(Strip), NameOfWrappedPass(NameOfWrappedPass) {}
+ CheckDebugifyModulePass(bool Strip = false, StringRef NameOfWrappedPass = "",
+ DebugifyStatsMap *StatsMap = nullptr)
+ : ModulePass(ID), Strip(Strip), NameOfWrappedPass(NameOfWrappedPass),
+ StatsMap(StatsMap) {}
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesAll();
@@ -346,6 +361,7 @@ struct CheckDebugifyModulePass : public ModulePass {
private:
bool Strip;
StringRef NameOfWrappedPass;
+ DebugifyStatsMap *StatsMap;
};
/// FunctionPass for checking debug info inserted by -debugify-function, used
@@ -356,12 +372,14 @@ struct CheckDebugifyFunctionPass : public FunctionPass {
auto FuncIt = F.getIterator();
return checkDebugifyMetadata(M, make_range(FuncIt, std::next(FuncIt)),
NameOfWrappedPass, "CheckFunctionDebugify",
- Strip);
+ Strip, StatsMap);
}
CheckDebugifyFunctionPass(bool Strip = false,
- StringRef NameOfWrappedPass = "")
- : FunctionPass(ID), Strip(Strip), NameOfWrappedPass(NameOfWrappedPass) {}
+ StringRef NameOfWrappedPass = "",
+ DebugifyStatsMap *StatsMap = nullptr)
+ : FunctionPass(ID), Strip(Strip), NameOfWrappedPass(NameOfWrappedPass),
+ StatsMap(StatsMap) {}
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesAll();
@@ -372,10 +390,32 @@ struct CheckDebugifyFunctionPass : public FunctionPass {
private:
bool Strip;
StringRef NameOfWrappedPass;
+ DebugifyStatsMap *StatsMap;
};
} // end anonymous namespace
+void exportDebugifyStats(llvm::StringRef Path, const DebugifyStatsMap &Map) {
+ std::error_code EC;
+ raw_fd_ostream OS{Path, EC};
+ if (EC) {
+ errs() << "Could not open file: " << EC.message() << ", " << Path << '\n';
+ return;
+ }
+
+ OS << "Pass Name" << ',' << "# of missing debug values" << ','
+ << "# of missing locations" << ',' << "Missing/Expected value ratio" << ','
+ << "Missing/Expected location ratio" << '\n';
+ for (const auto &Entry : Map) {
+ StringRef Pass = Entry.first;
+ DebugifyStatistics Stats = Entry.second;
+
+ OS << Pass << ',' << Stats.NumDbgValuesMissing << ','
+ << Stats.NumDbgLocsMissing << ',' << Stats.getMissingValueRatio() << ','
+ << Stats.getEmptyLocationRatio() << '\n';
+ }
+}
+
ModulePass *createDebugifyModulePass() { return new DebugifyModulePass(); }
FunctionPass *createDebugifyFunctionPass() {
@@ -388,18 +428,21 @@ PreservedAnalyses NewPMDebugifyPass::run(Module &M, ModuleAnalysisManager &) {
}
ModulePass *createCheckDebugifyModulePass(bool Strip,
- StringRef NameOfWrappedPass) {
- return new CheckDebugifyModulePass(Strip, NameOfWrappedPass);
+ StringRef NameOfWrappedPass,
+ DebugifyStatsMap *StatsMap) {
+ return new CheckDebugifyModulePass(Strip, NameOfWrappedPass, StatsMap);
}
FunctionPass *createCheckDebugifyFunctionPass(bool Strip,
- StringRef NameOfWrappedPass) {
- return new CheckDebugifyFunctionPass(Strip, NameOfWrappedPass);
+ StringRef NameOfWrappedPass,
+ DebugifyStatsMap *StatsMap) {
+ return new CheckDebugifyFunctionPass(Strip, NameOfWrappedPass, StatsMap);
}
PreservedAnalyses NewPMCheckDebugifyPass::run(Module &M,
ModuleAnalysisManager &) {
- checkDebugifyMetadata(M, M.functions(), "", "CheckModuleDebugify", false);
+ checkDebugifyMetadata(M, M.functions(), "", "CheckModuleDebugify", false,
+ nullptr);
return PreservedAnalyses::all();
}
diff --git a/llvm/tools/opt/Debugify.h b/llvm/tools/opt/Debugify.h
index 14ea5d3c6eb..d1a60c73e72 100644
--- a/llvm/tools/opt/Debugify.h
+++ b/llvm/tools/opt/Debugify.h
@@ -14,7 +14,10 @@
#ifndef LLVM_TOOLS_OPT_DEBUGIFY_H
#define LLVM_TOOLS_OPT_DEBUGIFY_H
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/MapVector.h"
#include "llvm/IR/PassManager.h"
+#include "llvm/Support/raw_ostream.h"
llvm::ModulePass *createDebugifyModulePass();
llvm::FunctionPass *createDebugifyFunctionPass();
@@ -23,13 +26,46 @@ struct NewPMDebugifyPass : public llvm::PassInfoMixin<NewPMDebugifyPass> {
llvm::PreservedAnalyses run(llvm::Module &M, llvm::ModuleAnalysisManager &AM);
};
+/// Track how much `debugify` information has been lost.
+struct DebugifyStatistics {
+ /// Number of missing dbg.values.
+ unsigned NumDbgValuesMissing = 0;
+
+ /// Number of dbg.values expected.
+ unsigned NumDbgValuesExpected = 0;
+
+ /// Number of instructions with empty debug locations.
+ unsigned NumDbgLocsMissing = 0;
+
+ /// Number of instructions expected to have debug locations.
+ unsigned NumDbgLocsExpected = 0;
+
+ /// Get the ratio of missing/expected dbg.values.
+ float getMissingValueRatio() const {
+ return float(NumDbgValuesMissing) / float(NumDbgLocsExpected);
+ }
+
+ /// Get the ratio of missing/expected instructions with locations.
+ float getEmptyLocationRatio() const {
+ return float(NumDbgLocsMissing) / float(NumDbgLocsExpected);
+ }
+};
+
+/// Map pass names to a per-pass DebugifyStatistics instance.
+using DebugifyStatsMap = llvm::MapVector<llvm::StringRef, DebugifyStatistics>;
+
+/// Export per-pass debugify statistics to the file specified by \p Path.
+void exportDebugifyStats(llvm::StringRef Path, const DebugifyStatsMap &Map);
+
llvm::ModulePass *
createCheckDebugifyModulePass(bool Strip = false,
- llvm::StringRef NameOfWrappedPass = "");
+ llvm::StringRef NameOfWrappedPass = "",
+ DebugifyStatsMap *StatsMap = nullptr);
llvm::FunctionPass *
createCheckDebugifyFunctionPass(bool Strip = false,
- llvm::StringRef NameOfWrappedPass = "");
+ llvm::StringRef NameOfWrappedPass = "",
+ DebugifyStatsMap *StatsMap = nullptr);
struct NewPMCheckDebugifyPass
: public llvm::PassInfoMixin<NewPMCheckDebugifyPass> {
diff --git a/llvm/tools/opt/opt.cpp b/llvm/tools/opt/opt.cpp
index 98ad700409c..6e287b6c0ab 100644
--- a/llvm/tools/opt/opt.cpp
+++ b/llvm/tools/opt/opt.cpp
@@ -217,6 +217,11 @@ static cl::opt<bool> DebugifyEach(
cl::desc(
"Start each pass with debugify and end it with check-debugify"));
+static cl::opt<std::string>
+ DebugifyExport("debugify-export",
+ cl::desc("Export per-pass debugify statistics to this file"),
+ cl::value_desc("filename"), cl::init(""));
+
static cl::opt<bool>
PrintBreakpoints("print-breakpoints-for-testing",
cl::desc("Print select breakpoints location for testing"));
@@ -267,34 +272,45 @@ static cl::opt<std::string>
cl::value_desc("filename"));
class OptCustomPassManager : public legacy::PassManager {
+ DebugifyStatsMap DIStatsMap;
+
public:
using super = legacy::PassManager;
void add(Pass *P) override {
+ // Wrap each pass with (-check)-debugify passes if requested, making
+ // exceptions for passes which shouldn't see -debugify instrumentation.
bool WrapWithDebugify = DebugifyEach && !P->getAsImmutablePass() &&
!isIRPrintingPass(P) && !isBitcodeWriterPass(P);
if (!WrapWithDebugify) {
super::add(P);
return;
}
+
+ // Apply -debugify/-check-debugify before/after each pass and collect
+ // debug info loss statistics.
PassKind Kind = P->getPassKind();
+ StringRef Name = P->getPassName();
+
// TODO: Implement Debugify for BasicBlockPass, LoopPass.
switch (Kind) {
case PT_Function:
super::add(createDebugifyFunctionPass());
super::add(P);
- super::add(createCheckDebugifyFunctionPass(true, P->getPassName()));
+ super::add(createCheckDebugifyFunctionPass(true, Name, &DIStatsMap));
break;
case PT_Module:
super::add(createDebugifyModulePass());
super::add(P);
- super::add(createCheckDebugifyModulePass(true, P->getPassName()));
+ super::add(createCheckDebugifyModulePass(true, Name, &DIStatsMap));
break;
default:
super::add(P);
break;
}
}
+
+ const DebugifyStatsMap &getDebugifyStatsMap() const { return DIStatsMap; }
};
static inline void addPass(legacy::PassManagerBase &PM, Pass *P) {
@@ -839,6 +855,9 @@ int main(int argc, char **argv) {
Out->os() << BOS->str();
}
+ if (DebugifyEach && !DebugifyExport.empty())
+ exportDebugifyStats(DebugifyExport, Passes.getDebugifyStatsMap());
+
// Declare success.
if (!NoOutput || PrintBreakpoints)
Out->keep();
OpenPOWER on IntegriCloud