[llvm] 7fb9bcd - [dsymutil] Add option to print statistics about the .debug_info size.

Jonas Devlieghere via llvm-commits llvm-commits at lists.llvm.org
Wed May 6 19:48:53 PDT 2020


Author: Jonas Devlieghere
Date: 2020-05-06T19:48:45-07:00
New Revision: 7fb9bcd3da64fee7b1116d703beb5db9ef2473bc

URL: https://github.com/llvm/llvm-project/commit/7fb9bcd3da64fee7b1116d703beb5db9ef2473bc
DIFF: https://github.com/llvm/llvm-project/commit/7fb9bcd3da64fee7b1116d703beb5db9ef2473bc.diff

LOG: [dsymutil] Add option to print statistics about the .debug_info size.

This patch adds statistics about the contribution of each object file to
the linked debug info. When --statistics is passed to dsymutil, it
prints a table after linking as illustrated below.

It lists the object file name, the size of the debug info in the object
file in bytes, and the absolute size contribution to the linked dSYM and
the percentage difference. The table is sorted by the output size, so
the object files contributing the most to the link are listed first.

.debug_info section size (in bytes)
-------------------------------------------------------------------------------
Filename                                           Object         dSYM   Change
-------------------------------------------------------------------------------
basic2.macho.x86_64.o                                210b         165b  -24.00%
basic3.macho.x86_64.o                                177b         150b  -16.51%
basic1.macho.x86_64.o                                125b         129b    3.15%
-------------------------------------------------------------------------------
Total                                                512b         444b  -14.23%
-------------------------------------------------------------------------------

Differential revision: https://reviews.llvm.org/D79513

Added: 
    llvm/test/tools/dsymutil/X86/statistics.test

Modified: 
    llvm/docs/CommandGuide/dsymutil.rst
    llvm/include/llvm/DWARFLinker/DWARFLinker.h
    llvm/lib/DWARFLinker/DWARFLinker.cpp
    llvm/test/tools/dsymutil/cmdline.test
    llvm/tools/dsymutil/DwarfLinkerForBinary.cpp
    llvm/tools/dsymutil/LinkUtils.h
    llvm/tools/dsymutil/Options.td
    llvm/tools/dsymutil/dsymutil.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/docs/CommandGuide/dsymutil.rst b/llvm/docs/CommandGuide/dsymutil.rst
index d86705ac8681..5e0140bf2041 100644
--- a/llvm/docs/CommandGuide/dsymutil.rst
+++ b/llvm/docs/CommandGuide/dsymutil.rst
@@ -77,7 +77,7 @@ OPTIONS
 
  Specifies an alternate ``path`` to place the dSYM bundle. The default dSYM
  bundle path is created by appending ``.dSYM`` to the executable name.
- 
+
 .. option:: --papertrail
 
  When running dsymutil as part of your build system, it can be desirable for
@@ -93,6 +93,14 @@ OPTIONS
 
  Specify a directory to prepend the paths of the external remark files.
 
+.. option:: --statistics
+
+ Print statistics about the contribution of each object file to the linked
+ debug info. This prints a table after linking with the object file name, the
+ size of the debug info in the object file (in bytes) and the size contributed
+ (in bytes) to the linked dSYM. The table is sorted by the output size listing
+ the obj ect files with the largest contribution first.
+
 .. option:: --symbol-map <bcsymbolmap>
 
  Update the existing dSYMs inplace using symbol map specified.

diff  --git a/llvm/include/llvm/DWARFLinker/DWARFLinker.h b/llvm/include/llvm/DWARFLinker/DWARFLinker.h
index d75ed8b98949..be3c5ebcadae 100644
--- a/llvm/include/llvm/DWARFLinker/DWARFLinker.h
+++ b/llvm/include/llvm/DWARFLinker/DWARFLinker.h
@@ -260,6 +260,9 @@ class DWARFLinker {
   /// Allows to generate log of linking process to the standard output.
   void setVerbosity(bool Verbose) { Options.Verbose = Verbose; }
 
+  /// Print statistics to standard output.
+  void setStatistics(bool Statistics) { Options.Statistics = Statistics; }
+
   /// Do not emit linked dwarf info.
   void setNoOutput(bool NoOut) { Options.NoOutput = NoOut; }
 
@@ -556,9 +559,10 @@ class DWARFLinker {
     /// Construct the output DIE tree by cloning the DIEs we
     /// chose to keep above. If there are no valid relocs, then there's
     /// nothing to clone/emit.
-    void cloneAllCompileUnits(DWARFContext &DwarfContext, const DwarfFile &File,
-                              OffsetsStringPool &StringPool,
-                              bool IsLittleEndian);
+    uint64_t cloneAllCompileUnits(DWARFContext &DwarfContext,
+                                  const DwarfFile &File,
+                                  OffsetsStringPool &StringPool,
+                                  bool IsLittleEndian);
 
   private:
     using AttributeSpec = DWARFAbbreviationDeclaration::AttributeSpec;
@@ -757,6 +761,9 @@ class DWARFLinker {
     /// Generate processing log to the standard output.
     bool Verbose = false;
 
+    /// Print statistics.
+    bool Statistics = false;
+
     /// Skip emitting output
     bool NoOutput = false;
 

diff  --git a/llvm/lib/DWARFLinker/DWARFLinker.cpp b/llvm/lib/DWARFLinker/DWARFLinker.cpp
index 2c3e2023bced..b85126e9063a 100644
--- a/llvm/lib/DWARFLinker/DWARFLinker.cpp
+++ b/llvm/lib/DWARFLinker/DWARFLinker.cpp
@@ -25,6 +25,7 @@
 #include "llvm/Support/Error.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/FormatVariadic.h"
 #include "llvm/Support/LEB128.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/ThreadPool.h"
@@ -32,6 +33,21 @@
 
 namespace llvm {
 
+/// Hold the input and output of the debug info size in bytes.
+struct DebugInfoSize {
+  uint64_t Input;
+  uint64_t Output;
+};
+
+/// Compute the total size of the debug info.
+static uint64_t getDebugInfoSize(DWARFContext &Dwarf) {
+  uint64_t Size = 0;
+  for (auto &Unit : Dwarf.compile_units()) {
+    Size += Unit->getLength();
+  }
+  return Size;
+}
+
 /// Similar to DWARFUnitSection::getUnitForOffset(), but returning our
 /// CompileUnit object instead.
 static CompileUnit *getUnitForOffset(const UnitListTy &Units, uint64_t Offset) {
@@ -2071,12 +2087,13 @@ Error DWARFLinker::loadClangModule(
   return Error::success();
 }
 
-void DWARFLinker::DIECloner::cloneAllCompileUnits(DWARFContext &DwarfContext,
-                                                  const DwarfFile &File,
-                                                  OffsetsStringPool &StringPool,
-                                                  bool IsLittleEndian) {
+uint64_t DWARFLinker::DIECloner::cloneAllCompileUnits(
+    DWARFContext &DwarfContext, const DwarfFile &File,
+    OffsetsStringPool &StringPool, bool IsLittleEndian) {
   uint64_t OutputDebugInfoSize =
       Linker.Options.NoOutput ? 0 : Emitter->getDebugInfoSectionSize();
+  const uint64_t StartOutputDebugInfoSize = OutputDebugInfoSize;
+
   for (auto &CurrentUnit : CompileUnits) {
     auto InputDIE = CurrentUnit->getOrigUnit().getUnitDIE();
     CurrentUnit->setStartOffset(OutputDebugInfoSize);
@@ -2141,6 +2158,8 @@ void DWARFLinker::DIECloner::cloneAllCompileUnits(DWARFContext &DwarfContext,
              CurrentUnit->computeNextUnitOffset());
     }
   }
+
+  return OutputDebugInfoSize - StartOutputDebugInfoSize;
 }
 
 void DWARFLinker::updateAccelKind(DWARFContext &Dwarf) {
@@ -2393,6 +2412,9 @@ bool DWARFLinker::link() {
     }
   };
 
+  // For each object file map how many bytes were emitted.
+  StringMap<DebugInfoSize> SizeByObject;
+
   // And then the remaining work in serial again.
   // Note, although this loop runs in serial, it can run in parallel with
   // the analyzeContextInfo loop so long as we process files with indices >=
@@ -2425,11 +2447,14 @@ bool DWARFLinker::link() {
     // need to reset the NextValidReloc index to the beginning.
     if (OptContext.File.Addresses->hasValidRelocs() ||
         LLVM_UNLIKELY(Options.Update)) {
-      DIECloner(*this, TheDwarfEmitter, OptContext.File, DIEAlloc,
-                OptContext.CompileUnits, Options.Update)
-          .cloneAllCompileUnits(*OptContext.File.Dwarf, OptContext.File,
-                                OffsetsStringPool,
-                                OptContext.File.Dwarf->isLittleEndian());
+      SizeByObject[OptContext.File.FileName].Input =
+          getDebugInfoSize(*OptContext.File.Dwarf);
+      SizeByObject[OptContext.File.FileName].Output =
+          DIECloner(*this, TheDwarfEmitter, OptContext.File, DIEAlloc,
+                    OptContext.CompileUnits, Options.Update)
+              .cloneAllCompileUnits(*OptContext.File.Dwarf, OptContext.File,
+                                    OffsetsStringPool,
+                                    OptContext.File.Dwarf->isLittleEndian());
     }
     if (!Options.NoOutput && !OptContext.CompileUnits.empty() &&
         LLVM_LIKELY(!Options.Update))
@@ -2505,6 +2530,53 @@ bool DWARFLinker::link() {
     Pool.wait();
   }
 
+  if (Options.Statistics) {
+    // Create a vector sorted in descending order by output size.
+    std::vector<std::pair<StringRef, DebugInfoSize>> Sorted;
+    for (auto &E : SizeByObject)
+      Sorted.emplace_back(E.first(), E.second);
+    sort(Sorted.begin(), Sorted.end(), [](auto &LHS, auto &RHS) {
+      return LHS.second.Output > RHS.second.Output;
+    });
+
+    auto ComputePercentange = [](int64_t Input, int64_t Output) -> float {
+      const float Difference = Output - Input;
+      const float Sum = Input + Output;
+      if (Sum == 0)
+        return 0;
+      return (Difference / (Sum / 2));
+    };
+
+    int64_t InputTotal = 0;
+    int64_t OutputTotal = 0;
+    const char *FormatStr = "{0,-45} {1,10}b  {2,10}b {3,8:P}\n";
+
+    // Print header.
+    outs() << ".debug_info section size (in bytes)\n";
+    outs() << "----------------------------------------------------------------"
+              "---------------\n";
+    outs() << "Filename                                           Object       "
+              "  dSYM   Change\n";
+    outs() << "----------------------------------------------------------------"
+              "---------------\n";
+
+    // Print body.
+    for (auto &E : Sorted) {
+      InputTotal += E.second.Input;
+      OutputTotal += E.second.Output;
+      llvm::outs() << formatv(
+          FormatStr, sys::path::filename(E.first).take_back(45), E.second.Input,
+          E.second.Output, ComputePercentange(E.second.Input, E.second.Output));
+    }
+    // Print total and footer.
+    outs() << "----------------------------------------------------------------"
+              "---------------\n";
+    llvm::outs() << formatv(FormatStr, "Total", InputTotal, OutputTotal,
+                            ComputePercentange(InputTotal, OutputTotal));
+    outs() << "----------------------------------------------------------------"
+              "---------------\n\n";
+  }
+
   return true;
 }
 

diff  --git a/llvm/test/tools/dsymutil/X86/statistics.test b/llvm/test/tools/dsymutil/X86/statistics.test
new file mode 100644
index 000000000000..0237aede2800
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/statistics.test
@@ -0,0 +1,21 @@
+# RUN: dsymutil -statistics -oso-prepend-path=%p/.. %p/../Inputs/basic.macho.x86_64 %p/../Inputs/basic-archive.macho.x86_64 %p/../Inputs/basic-lto.macho.x86_64 %p/../Inputs/basic-lto-dw4.macho.x86_64 -o %t 2>&1 | FileCheck %s
+#
+# CHECK: -------------------------------------------------------------------------------
+# CHECK-NEXT: Filename                                           Object         dSYM   Change
+# CHECK-NEXT: -------------------------------------------------------------------------------
+# CHECK-DAG: basic2.macho.x86_64.o {{[0-9]+}}b {{[0-9]+}}b{{.*}}{{[0-9]+}}.{{[0-9]+}}%
+# CHECK-DAG: basic3.macho.x86_64.o {{[0-9]+}}b {{[0-9]+}}b{{.*}}{{[0-9]+}}.{{[0-9]+}}%
+# CHECK-DAG: basic1.macho.x86_64.o {{[0-9]+}}b {{[0-9]+}}b{{.*}}{{[0-9]+}}.{{[0-9]+}}%
+# CHECK: -------------------------------------------------------------------------------
+# CHECK-NEXT: Total                {{[0-9]+}}b {{[0-9]+}}b{{.*}}{{[0-9]+}}.{{[0-9]+}}%
+# CHECK-NEXT: -------------------------------------------------------------------------------
+
+---
+triple:          'x86_64-apple-darwin'
+objects:
+  - filename:        invalid.o
+    timestamp:       1518197670
+    symbols:
+      - { sym: _main, objAddr: 0x0000000000000010, binAddr: 0x0000000100000FB0, size: 0x00000008 }
+      - { sym: _g, objAddr: 0x0000000000000000, binAddr: 0x0000000100000FA0, size: 0x00000010 }
+...

diff  --git a/llvm/test/tools/dsymutil/cmdline.test b/llvm/test/tools/dsymutil/cmdline.test
index e66f4a589fba..c1347ead0565 100644
--- a/llvm/test/tools/dsymutil/cmdline.test
+++ b/llvm/test/tools/dsymutil/cmdline.test
@@ -18,6 +18,7 @@ HELP: {{ -o <filename> }}
 HELP: -papertrail
 HELP: -remarks-output-format <format>
 HELP: -remarks-prepend-path <path>
+HELP: -statistics
 HELP: -symbol-map
 HELP: -symtab
 HELP: {{ -S }}

diff  --git a/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp b/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp
index 0612fd57a2dd..07237e220c31 100644
--- a/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp
+++ b/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp
@@ -315,6 +315,7 @@ bool DwarfLinkerForBinary::link(const DebugMap &Map) {
   };
 
   GeneralLinker.setVerbosity(Options.Verbose);
+  GeneralLinker.setStatistics(Options.Statistics);
   GeneralLinker.setNoOutput(Options.NoOutput);
   GeneralLinker.setNoODR(Options.NoODR);
   GeneralLinker.setUpdate(Options.Update);

diff  --git a/llvm/tools/dsymutil/LinkUtils.h b/llvm/tools/dsymutil/LinkUtils.h
index eef3338908be..52b36353c6b6 100644
--- a/llvm/tools/dsymutil/LinkUtils.h
+++ b/llvm/tools/dsymutil/LinkUtils.h
@@ -27,6 +27,9 @@ struct LinkOptions {
   /// Verbosity
   bool Verbose = false;
 
+  /// Statistics
+  bool Statistics = false;
+
   /// Skip emitting output
   bool NoOutput = false;
 

diff  --git a/llvm/tools/dsymutil/Options.td b/llvm/tools/dsymutil/Options.td
index 9292fb802151..1542a94636bb 100644
--- a/llvm/tools/dsymutil/Options.td
+++ b/llvm/tools/dsymutil/Options.td
@@ -24,6 +24,15 @@ def verbose: F<"verbose">,
   HelpText<"Enable verbose mode.">,
   Group<grp_general>;
 
+def statistics: F<"statistics">,
+  HelpText<"Print statistics about the contribution of each object file to "
+           "the linked debug info. This prints a table after linking with the "
+           "object file name, the size of the debug info in the object file "
+           "(in bytes) and the size contributed (in bytes) to the linked dSYM. "
+           "The table is sorted by the output size listing the object files "
+           "with the largest contribution first.">,
+  Group<grp_general>;
+
 def verify: F<"verify">,
   HelpText<"Run the DWARF verifier on the linked DWARF debug info.">,
   Group<grp_general>;

diff  --git a/llvm/tools/dsymutil/dsymutil.cpp b/llvm/tools/dsymutil/dsymutil.cpp
index 78503a02ec00..8ea89933e362 100644
--- a/llvm/tools/dsymutil/dsymutil.cpp
+++ b/llvm/tools/dsymutil/dsymutil.cpp
@@ -220,6 +220,7 @@ static Expected<DsymutilOptions> getOptions(opt::InputArgList &Args) {
   Options.LinkOpts.NoTimestamp = Args.hasArg(OPT_no_swiftmodule_timestamp);
   Options.LinkOpts.Update = Args.hasArg(OPT_update);
   Options.LinkOpts.Verbose = Args.hasArg(OPT_verbose);
+  Options.LinkOpts.Statistics = Args.hasArg(OPT_statistics);
 
   if (Expected<AccelTableKind> AccelKind = getAccelTableKind(Args)) {
     Options.LinkOpts.TheAccelTableKind = *AccelKind;
@@ -548,7 +549,11 @@ int main(int argc, char **argv) {
     // Shared a single binary holder for all the link steps.
     BinaryHolder BinHolder(Options.LinkOpts.VFS);
 
-    ThreadPoolStrategy S = hardware_concurrency(Options.LinkOpts.Threads);
+    // Statistics only require 
diff erent architectures to be processed
+    // sequentially, the link itself can still happen in parallel. Change the
+    // thread pool strategy here instead of modifying LinkOpts.Threads.
+    ThreadPoolStrategy S = hardware_concurrency(
+        Options.LinkOpts.Statistics ? 1 : Options.LinkOpts.Threads);
     if (Options.LinkOpts.Threads == 0) {
       // If NumThreads is not specified, create one thread for each input, up to
       // the number of hardware threads.


        


More information about the llvm-commits mailing list