Index: lld/trunk/COFF/Config.h =================================================================== --- lld/trunk/COFF/Config.h +++ lld/trunk/COFF/Config.h @@ -102,6 +102,7 @@ bool DebugGHashes = false; bool DebugSymtab = false; bool ShowTiming = false; + bool ShowSummary = false; unsigned DebugTypes = static_cast(DebugType::None); std::vector NatvisFiles; llvm::SmallString<128> PDBAltPath; Index: lld/trunk/COFF/Driver.cpp =================================================================== --- lld/trunk/COFF/Driver.cpp +++ lld/trunk/COFF/Driver.cpp @@ -1000,6 +1000,8 @@ if (Args.hasArg(OPT_show_timing)) Config->ShowTiming = true; + Config->ShowSummary = Args.hasArg(OPT_summary); + ScopedTimer T(Timer::root()); // Handle --version, which is an lld extension. This option is a bit odd // because it doesn't start with "/", but we deliberately chose "--" to Index: lld/trunk/COFF/Options.td =================================================================== --- lld/trunk/COFF/Options.td +++ lld/trunk/COFF/Options.td @@ -174,6 +174,7 @@ def lldmap : F<"lldmap">; def lldmap_file : Joined<["/", "-"], "lldmap:">; def show_timing : F<"time">; +def summary : F<"summary">; //============================================================================== // The flags below do nothing. They are defined only for link.exe compatibility. Index: lld/trunk/COFF/PDB.cpp =================================================================== --- lld/trunk/COFF/PDB.cpp +++ lld/trunk/COFF/PDB.cpp @@ -180,6 +180,9 @@ /// Write the PDB to disk and store the Guid generated for it in *Guid. void commit(codeview::GUID *Guid); + // Print statistics regarding the final PDB + void printStats(); + private: BumpPtrAllocator Alloc; @@ -222,6 +225,11 @@ /// List of TypeServer PDBs which cannot be loaded. /// Cached to prevent repeated load attempts. std::map MissingTypeServerPDBs; + + // For statistics + uint64_t GlobalSymbols = 0; + uint64_t ModuleSymbols = 0; + uint64_t PublicSymbols = 0; }; class DebugSHandler { @@ -1041,9 +1049,11 @@ // adding the symbol to the module since we may need to get the next // symbol offset, and writing to the module's symbol stream will update // that offset. - if (symbolGoesInGlobalsStream(Sym, Scopes.empty())) + if (symbolGoesInGlobalsStream(Sym, Scopes.empty())) { addGlobalSymbol(Builder.getGsiBuilder(), File->ModuleDBI->getModuleIndex(), CurSymOffset, Sym); + ++GlobalSymbols; + } if (symbolGoesInModuleStream(Sym, Scopes.empty())) { // Add symbols to the module in bulk. If this symbol is contiguous @@ -1057,6 +1067,7 @@ BulkSymbols = RecordBytes; } CurSymOffset += Sym.length(); + ++ModuleSymbols; } return Error::success(); })); @@ -1339,6 +1350,7 @@ }); if (!Publics.empty()) { + PublicSymbols = Publics.size(); // Sort the public symbols and add them to the stream. parallelSort(Publics, [](const PublicSym32 &L, const PublicSym32 &R) { return L.Name < R.Name; @@ -1348,6 +1360,33 @@ } } +void PDBLinker::printStats() { + if (!Config->ShowSummary) + return; + + SmallString<256> Buffer; + raw_svector_ostream Stream(Buffer); + + Stream << center_justify("Summary", 80) << '\n' + << std::string(80, '-') << '\n'; + + auto Print = [&](uint64_t V, StringRef S) { + Stream << format_decimal(V, 15) << " " << S << '\n'; + }; + + Print(ObjFile::Instances.size(), + "Input OBJ files (expanded from all cmd-line inputs)"); + Print(TypeServerIndexMappings.size(), "PDB type server dependencies"); + Print(PrecompTypeIndexMappings.size(), "Precomp OBJ dependencies"); + Print(getTypeTable().size() + getIDTable().size(), "Merged TPI records"); + Print(PDBStrTab.size(), "Output PDB strings"); + Print(GlobalSymbols, "Global symbol records"); + Print(ModuleSymbols, "Module symbol records"); + Print(PublicSymbols, "Public symbol records"); + + message(Buffer); +} + void PDBLinker::addNatvisFiles() { for (StringRef File : Config->NatvisFiles) { ErrorOr> DataOrErr = @@ -1493,6 +1532,10 @@ codeview::GUID Guid; PDB.commit(&Guid); memcpy(&BuildId->PDB70.Signature, &Guid, 16); + + T2.stop(); + T1.stop(); + PDB.printStats(); } void PDBLinker::initialize(llvm::codeview::DebugInfo *BuildId) { Index: lld/trunk/test/COFF/pdb-type-server-simple.test =================================================================== --- lld/trunk/test/COFF/pdb-type-server-simple.test +++ lld/trunk/test/COFF/pdb-type-server-simple.test @@ -20,7 +20,7 @@ RUN: yaml2obj %S/Inputs/pdb-type-server-simple-a.yaml -o a.obj RUN: yaml2obj %S/Inputs/pdb-type-server-simple-b.yaml -o b.obj RUN: llvm-pdbutil yaml2pdb %S/Inputs/pdb-type-server-simple-ts.yaml -pdb ts.pdb -RUN: lld-link a.obj b.obj -entry:main -debug -out:t.exe -pdb:t.pdb -nodefaultlib +RUN: lld-link a.obj b.obj -entry:main -debug -out:t.exe -pdb:t.pdb -nodefaultlib /summary | FileCheck %s -check-prefix SUMMARY RUN: llvm-pdbutil dump -symbols -types -ids -globals %t/t.pdb | FileCheck %s @@ -95,3 +95,14 @@ CHECK: 196 | S_END [size = 4] CHECK: 200 | S_BUILDINFO [size = 8] BuildId = `[[B_BUILD]]` CHECK-LABEL: Mod 0002 | `* Linker *`: + +SUMMARY: Summary +SUMMARY-NEXT: -------------------------------------------------------------------------------- +SUMMARY-NEXT: 2 Input OBJ files (expanded from all cmd-line inputs) +SUMMARY-NEXT: 1 PDB type server dependencies +SUMMARY-NEXT: 0 Precomp OBJ dependencies +SUMMARY-NEXT: 25 Merged TPI records +SUMMARY-NEXT: 3 Output PDB strings +SUMMARY-NEXT: 4 Global symbol records +SUMMARY-NEXT: 14 Module symbol records +SUMMARY-NEXT: 2 Public symbol records \ No newline at end of file Index: lld/trunk/test/COFF/precomp-link.test =================================================================== --- lld/trunk/test/COFF/precomp-link.test +++ lld/trunk/test/COFF/precomp-link.test @@ -1,4 +1,4 @@ -RUN: lld-link %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj %S/Inputs/precomp.obj /nodefaultlib /entry:main /debug /pdb:%t.pdb /out:%t.exe /opt:ref /opt:icf +RUN: lld-link %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj %S/Inputs/precomp.obj /nodefaultlib /entry:main /debug /pdb:%t.pdb /out:%t.exe /opt:ref /opt:icf /summary | FileCheck %s -check-prefix SUMMARY RUN: llvm-pdbutil dump -types %t.pdb | FileCheck %s RUN: lld-link %S/Inputs/precomp.obj %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj /nodefaultlib /entry:main /debug /pdb:%t.pdb /out:%t.exe /opt:ref /opt:icf @@ -18,6 +18,18 @@ CHECK-NOT: LF_PRECOMP CHECK-NOT: LF_ENDPRECOMP + +SUMMARY: Summary +SUMMARY-NEXT: -------------------------------------------------------------------------------- +SUMMARY-NEXT: 3 Input OBJ files (expanded from all cmd-line inputs) +SUMMARY-NEXT: 0 PDB type server dependencies +SUMMARY-NEXT: 1 Precomp OBJ dependencies +SUMMARY-NEXT: 1044 Merged TPI records +SUMMARY-NEXT: 5 Output PDB strings +SUMMARY-NEXT: 167 Global symbol records +SUMMARY-NEXT: 20 Module symbol records +SUMMARY-NEXT: 3 Public symbol records + // precomp.h #pragma once int Function(char A);