[llvm] r337787 - [Debugify] Export per-pass debug info loss statistics

Vedant Kumar via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 23 17:41:29 PDT 2018


Author: vedantk
Date: Mon Jul 23 17:41:29 2018
New Revision: 337787

URL: http://llvm.org/viewvc/llvm-project?rev=337787&view=rev
Log:
[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

Added:
    llvm/trunk/test/DebugInfo/debugify-export.ll
Modified:
    llvm/trunk/tools/opt/Debugify.cpp
    llvm/trunk/tools/opt/Debugify.h
    llvm/trunk/tools/opt/opt.cpp

Added: llvm/trunk/test/DebugInfo/debugify-export.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/debugify-export.ll?rev=337787&view=auto
==============================================================================
--- llvm/trunk/test/DebugInfo/debugify-export.ll (added)
+++ llvm/trunk/test/DebugInfo/debugify-export.ll Mon Jul 23 17:41:29 2018
@@ -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
+}

Modified: llvm/trunk/tools/opt/Debugify.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/opt/Debugify.cpp?rev=337787&r1=337786&r2=337787&view=diff
==============================================================================
--- llvm/trunk/tools/opt/Debugify.cpp (original)
+++ llvm/trunk/tools/opt/Debugify.cpp Mon Jul 23 17:41:29 2018
@@ -209,7 +209,7 @@ bool diagnoseMisSizedDbgValue(Module &M,
 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 Fun
 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
 private:
   bool Strip;
   StringRef NameOfWrappedPass;
+  DebugifyStatsMap *StatsMap;
 };
 
 /// FunctionPass for checking debug info inserted by -debugify-function, used
@@ -356,12 +372,14 @@ struct CheckDebugifyFunctionPass : publi
     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 : publi
 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
 }
 
 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();
 }
 

Modified: llvm/trunk/tools/opt/Debugify.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/opt/Debugify.h?rev=337787&r1=337786&r2=337787&view=diff
==============================================================================
--- llvm/trunk/tools/opt/Debugify.h (original)
+++ llvm/trunk/tools/opt/Debugify.h Mon Jul 23 17:41:29 2018
@@ -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::
   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> {

Modified: llvm/trunk/tools/opt/opt.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/opt/opt.cpp?rev=337787&r1=337786&r2=337787&view=diff
==============================================================================
--- llvm/trunk/tools/opt/opt.cpp (original)
+++ llvm/trunk/tools/opt/opt.cpp Mon Jul 23 17:41:29 2018
@@ -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();




More information about the llvm-commits mailing list