[lld] b912b88 - [ELF] Add --print-archive-stats=
Fangrui Song via llvm-commits
llvm-commits at lists.llvm.org
Wed Apr 29 18:09:01 PDT 2020
Author: Fangrui Song
Date: 2020-04-29T18:04:37-07:00
New Revision: b912b887d87c96a7ef900091cf11610a08a98c24
URL: https://github.com/llvm/llvm-project/commit/b912b887d87c96a7ef900091cf11610a08a98c24
DIFF: https://github.com/llvm/llvm-project/commit/b912b887d87c96a7ef900091cf11610a08a98c24.diff
LOG: [ELF] Add --print-archive-stats=
gold has an option --print-symbol-counts= which prints:
// For each archive
archive $archive $members $fetched_members
// For each object file
symbols $object $defined_symbols $used_defined_symbols
In most cases, `$defined_symbols = $used_defined_symbols` unless weak
symbols are present. Strangely `$used_defined_symbols` includes symbols defined relative to --gc-sections discarded sections.
The `symbols` lines do not appear to be useful.
`archive` lines are useful: `$fetched_members=0` lines correspond to
unused archives. The information can be used to trim dependencies.
This patch implements --print-archive-stats= which prints the number of
members and the number of fetched members for each archive.
Reviewed By: grimar
Differential Revision: https://reviews.llvm.org/D78983
Added:
lld/test/ELF/print-archive-stats.s
Modified:
lld/ELF/Config.h
lld/ELF/Driver.cpp
lld/ELF/InputFiles.cpp
lld/ELF/InputFiles.h
lld/ELF/MapFile.cpp
lld/ELF/MapFile.h
lld/ELF/Options.td
lld/ELF/Writer.cpp
lld/docs/ld.lld.1
Removed:
################################################################################
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index cf2c70c4b99a..7e5ee7acef08 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -110,6 +110,7 @@ struct Configuration {
llvm::StringRef optRemarksPasses;
llvm::StringRef optRemarksFormat;
llvm::StringRef progName;
+ llvm::StringRef printArchiveStats;
llvm::StringRef printSymbolOrder;
llvm::StringRef soName;
llvm::StringRef sysroot;
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 31a2a3a3a860..4fa1d60826d0 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -90,6 +90,7 @@ bool link(ArrayRef<const char *> args, bool canExitEarly, raw_ostream &stdoutOS,
inputSections.clear();
outputSections.clear();
+ archiveFiles.clear();
binaryFiles.clear();
bitcodeFiles.clear();
lazyObjFiles.clear();
@@ -955,6 +956,7 @@ static void readConfigs(opt::InputArgList &args) {
args.hasFlag(OPT_print_icf_sections, OPT_no_print_icf_sections, false);
config->printGcSections =
args.hasFlag(OPT_print_gc_sections, OPT_no_print_gc_sections, false);
+ config->printArchiveStats = args.getLastArgValue(OPT_print_archive_stats);
config->printSymbolOrder =
args.getLastArgValue(OPT_print_symbol_order);
config->rpath = getRpath(args);
diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp
index f3dd11fde3f6..e3cf340cabe1 100644
--- a/lld/ELF/InputFiles.cpp
+++ b/lld/ELF/InputFiles.cpp
@@ -55,6 +55,7 @@ std::string toString(const elf::InputFile *f) {
namespace elf {
bool InputFile::isInGroup;
uint32_t InputFile::nextGroupId;
+std::vector<ArchiveFile *> archiveFiles;
std::vector<BinaryFile *> binaryFiles;
std::vector<BitcodeFile *> bitcodeFiles;
std::vector<LazyObjFile *> lazyObjFiles;
@@ -173,6 +174,7 @@ template <class ELFT> static void doParseFile(InputFile *file) {
// .a file
if (auto *f = dyn_cast<ArchiveFile>(file)) {
+ archiveFiles.push_back(f);
f->parse();
return;
}
@@ -1165,6 +1167,19 @@ void ArchiveFile::fetch(const Archive::Symbol &sym) {
parseFile(file);
}
+size_t ArchiveFile::getMemberCount() const {
+ size_t count = 0;
+ Error err = Error::success();
+ for (const Archive::Child &c : file->children(err)) {
+ (void)c;
+ ++count;
+ }
+ // This function is used by --print-archive-stats=, where an error does not
+ // really matter.
+ consumeError(std::move(err));
+ return count;
+}
+
unsigned SharedFile::vernauxNum;
// Parse the version definitions in the object file if present, and return a
diff --git a/lld/ELF/InputFiles.h b/lld/ELF/InputFiles.h
index d08c533e047b..48146e60e63e 100644
--- a/lld/ELF/InputFiles.h
+++ b/lld/ELF/InputFiles.h
@@ -326,6 +326,9 @@ class ArchiveFile : public InputFile {
// more than once.)
void fetch(const Archive::Symbol &sym);
+ size_t getMemberCount() const;
+ size_t getFetchedMemberCount() const { return seen.size(); }
+
private:
std::unique_ptr<Archive> file;
llvm::DenseSet<uint64_t> seen;
@@ -387,6 +390,7 @@ inline bool isBitcode(MemoryBufferRef mb) {
std::string replaceThinLTOSuffix(StringRef path);
+extern std::vector<ArchiveFile *> archiveFiles;
extern std::vector<BinaryFile *> binaryFiles;
extern std::vector<BitcodeFile *> bitcodeFiles;
extern std::vector<LazyObjFile *> lazyObjFiles;
diff --git a/lld/ELF/MapFile.cpp b/lld/ELF/MapFile.cpp
index e5f5c4f4ff23..42181574d106 100644
--- a/lld/ELF/MapFile.cpp
+++ b/lld/ELF/MapFile.cpp
@@ -259,5 +259,23 @@ void writeCrossReferenceTable() {
}
}
+void writeArchiveStats() {
+ if (config->printArchiveStats.empty())
+ return;
+
+ std::error_code ec;
+ raw_fd_ostream os(config->printArchiveStats, ec, sys::fs::OF_None);
+ if (ec) {
+ error("--print-archive-stats=: cannot open " + config->printArchiveStats +
+ ": " + ec.message());
+ return;
+ }
+
+ os << "members\tfetched\tarchive\n";
+ for (const ArchiveFile *f : archiveFiles)
+ os << f->getMemberCount() << '\t' << f->getFetchedMemberCount() << '\t'
+ << f->getName() << '\n';
+}
+
} // namespace elf
} // namespace lld
diff --git a/lld/ELF/MapFile.h b/lld/ELF/MapFile.h
index 7e7938919edf..c4da18f8ad7f 100644
--- a/lld/ELF/MapFile.h
+++ b/lld/ELF/MapFile.h
@@ -13,6 +13,7 @@ namespace lld {
namespace elf {
void writeMapFile();
void writeCrossReferenceTable();
+void writeArchiveStats();
} // namespace elf
} // namespace lld
diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td
index cb0c12a9a320..ae32cab5c33b 100644
--- a/lld/ELF/Options.td
+++ b/lld/ELF/Options.td
@@ -294,6 +294,10 @@ defm print_icf_sections: B<"print-icf-sections",
"List identical folded sections",
"Do not list identical folded sections (default)">;
+def print_archive_stats: J<"print-archive-stats=">,
+ HelpText<"Write archive usage statistics to the specified file. "
+ "Print the numbers of members and fetched members for each archive">;
+
defm print_symbol_order: Eq<"print-symbol-order",
"Print a symbol order specified by --call-graph-ordering-file into the specified file">;
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index bca5989861f9..6236ac51b1bb 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -601,11 +601,13 @@ template <class ELFT> void Writer<ELFT>::run() {
for (OutputSection *sec : outputSections)
sec->addr = 0;
- // Handle --print-map(-M)/--Map and --cref. Dump them before checkSections()
- // because the files may be useful in case checkSections() or openFile()
- // fails, for example, due to an erroneous file size.
+ // Handle --print-map(-M)/--Map, --cref and --print-archive-stats=. Dump them
+ // before checkSections() because the files may be useful in case
+ // checkSections() or openFile() fails, for example, due to an erroneous file
+ // size.
writeMapFile();
writeCrossReferenceTable();
+ writeArchiveStats();
if (config->checkSections)
checkSections();
diff --git a/lld/docs/ld.lld.1 b/lld/docs/ld.lld.1
index 1d55cf052c9b..54c0d7162d6b 100644
--- a/lld/docs/ld.lld.1
+++ b/lld/docs/ld.lld.1
@@ -414,6 +414,9 @@ List removed unused sections.
List identical folded sections.
.It Fl -print-map
Print a link map to the standard output.
+.It Fl -print-archive-stats Ns = Ns Ar file
+Write archive usage statistics to the specified file.
+Print the numbers of members and fetched members for each archive.
.It Fl -push-state
Save the current state of
.Fl -as-needed ,
diff --git a/lld/test/ELF/print-archive-stats.s b/lld/test/ELF/print-archive-stats.s
new file mode 100644
index 000000000000..3f5c4820f0c6
--- /dev/null
+++ b/lld/test/ELF/print-archive-stats.s
@@ -0,0 +1,38 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
+# RUN: echo '.globl weak; weak:' | llvm-mc -filetype=obj -triple=x86_64 - -o %tweak.o
+# RUN: echo '.global foo; foo:' | llvm-mc -filetype=obj -triple=x86_64 - -o %t1.o
+# RUN: echo '.global bar; bar:' | llvm-mc -filetype=obj -triple=x86_64 - -o %t2.o
+# RUN: echo '.global baz; baz:' | llvm-mc -filetype=obj -triple=x86_64 - -o %t3.o
+# RUN: rm -f %tweak.a && llvm-ar rc %tweak.a %tweak.o
+# RUN: rm -f %t1.a && llvm-ar rc %t1.a %t1.o %t2.o %t3.o
+
+# RUN: ld.lld %t.o %tweak.a %t1.a --print-archive-stats=%t.txt -o /dev/null
+# RUN: FileCheck --input-file=%t.txt -DT=%t %s --match-full-lines --strict-whitespace
+
+## Fetches 0 member from %tweak.a and 2 members from %t1.a
+# CHECK:members fetched archive
+# CHECK-NEXT:1 0 [[T]]weak.a
+# CHECK-NEXT:3 2 [[T]]1.a
+
+## - means stdout.
+# RUN: ld.lld %t.o %tweak.a %t1.a --print-archive-stats=- -o /dev/null |
diff %t.txt -
+
+## The second %t1.a has 0 fetched member.
+# RUN: ld.lld %t.o %tweak.a %t1.a %t1.a --print-archive-stats=- -o /dev/null | \
+# RUN: FileCheck --check-prefix=CHECK2 %s
+# CHECK2: members fetched archive
+# CHECK2-NEXT: 1 0 {{.*}}weak.a
+# CHECK2-NEXT: 3 2 {{.*}}1.a
+# CHECK2-NEXT: 3 0 {{.*}}1.a
+
+# RUN: not ld.lld -shared %t.o --print-archive-stats=/ -o /dev/null 2>&1 | FileCheck --check-prefix=ERR %s
+# ERR: error: --print-archive-stats=: cannot open /: {{.*}}
+
+.globl _start
+.weak weak
+_start:
+ call foo
+ call bar
+ call weak
More information about the llvm-commits
mailing list