1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-25 04:02:41 +01:00

[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
This commit is contained in:
Jonas Devlieghere 2020-05-06 19:38:30 -07:00
parent 3a0e9df3e1
commit 5e66aeab68
9 changed files with 141 additions and 14 deletions

View File

@ -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.

View File

@ -260,6 +260,9 @@ public:
/// 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 @@ private:
/// 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 @@ private:
/// Generate processing log to the standard output.
bool Verbose = false;
/// Print statistics.
bool Statistics = false;
/// Skip emitting output
bool NoOutput = false;

View File

@ -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;
}

View File

@ -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 }
...

View File

@ -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 }}

View File

@ -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);

View File

@ -27,6 +27,9 @@ struct LinkOptions {
/// Verbosity
bool Verbose = false;
/// Statistics
bool Statistics = false;
/// Skip emitting output
bool NoOutput = false;

View File

@ -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>;

View File

@ -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 different 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.