From 29d9e6a569a2030680f9cfee4275c6fbb7311df9 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Fri, 22 Mar 2019 21:22:13 +0000 Subject: [PATCH] [pdb] Add -type-stats and sort stats by descending size Summary: It prints this on chromium browser_tests.exe.pdb: Types Total: 5647475 entries ( 371,897,512 bytes, 65.85 avg) -------------------------------------------------------------------------- LF_CLASS: 397894 entries ( 119,537,780 bytes, 300.43 avg) LF_STRUCTURE: 236351 entries ( 83,208,084 bytes, 352.05 avg) LF_FIELDLIST: 291003 entries ( 66,087,920 bytes, 227.10 avg) LF_MFUNCTION: 1884176 entries ( 52,756,928 bytes, 28.00 avg) LF_POINTER: 1149030 entries ( 13,877,344 bytes, 12.08 avg) LF_ARGLIST: 789980 entries ( 12,436,752 bytes, 15.74 avg) LF_METHODLIST: 361498 entries ( 8,351,008 bytes, 23.10 avg) LF_ENUM: 16069 entries ( 6,108,340 bytes, 380.13 avg) LF_PROCEDURE: 269374 entries ( 4,309,984 bytes, 16.00 avg) LF_MODIFIER: 235602 entries ( 2,827,224 bytes, 12.00 avg) LF_UNION: 9131 entries ( 2,072,168 bytes, 226.94 avg) LF_VFTABLE: 323 entries ( 207,784 bytes, 643.29 avg) LF_ARRAY: 6639 entries ( 106,380 bytes, 16.02 avg) LF_VTSHAPE: 126 entries ( 6,472 bytes, 51.37 avg) LF_BITFIELD: 278 entries ( 3,336 bytes, 12.00 avg) LF_LABEL: 1 entries ( 8 bytes, 8.00 avg) The PDB is overall 1.9GB, so the LF_CLASS and LF_STRUCTURE declarations account for about 10% of the overall file size. I was surprised to find that on average LF_FIELDLIST records are short. Maybe this is because there are many more types with short member lists than there are instantiations with lots of members, like std::vector. Reviewers: aganea, zturner Subscribers: llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D59672 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@356813 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/DebugInfo/PDB/module-stats.test | 38 ++++++++--------- test/DebugInfo/PDB/type-stats.test | 17 ++++++++ test/DebugInfo/PDB/udt-stats.test | 6 +-- tools/llvm-pdbutil/DumpOutputStyle.cpp | 76 ++++++++++++++++++++++++++++++---- tools/llvm-pdbutil/DumpOutputStyle.h | 5 +++ tools/llvm-pdbutil/llvm-pdbutil.cpp | 5 ++- tools/llvm-pdbutil/llvm-pdbutil.h | 1 + 7 files changed, 117 insertions(+), 31 deletions(-) create mode 100644 test/DebugInfo/PDB/type-stats.test diff --git a/test/DebugInfo/PDB/module-stats.test b/test/DebugInfo/PDB/module-stats.test index c2c58339ae0..cb0204d6361 100644 --- a/test/DebugInfo/PDB/module-stats.test +++ b/test/DebugInfo/PDB/module-stats.test @@ -6,28 +6,28 @@ ALL-NEXT: Stream 12, 308 bytes ALL: Symbols ALL-NEXT: Total: 6 entries ( 204 bytes) ALL-NEXT: -------------------------------------------------------------------------- +ALL-NEXT: S_COMPILE3: 1 entries ( 60 bytes) +ALL-NEXT: S_OBJNAME: 1 entries ( 56 bytes) ALL-NEXT: S_GPROC32: 1 entries ( 44 bytes) ALL-NEXT: S_FRAMEPROC: 1 entries ( 32 bytes) -ALL-NEXT: S_END: 1 entries ( 4 bytes) -ALL-NEXT: S_OBJNAME: 1 entries ( 56 bytes) -ALL-NEXT: S_COMPILE3: 1 entries ( 60 bytes) ALL-NEXT: S_BUILDINFO: 1 entries ( 8 bytes) +ALL-NEXT: S_END: 1 entries ( 4 bytes) ALL: Chunks ALL-NEXT: Total: 2 entries ( 88 bytes) ALL-NEXT: -------------------------------------------------------------------------- -ALL-NEXT: DEBUG_S_FILECHKSMS: 1 entries ( 32 bytes) ALL-NEXT: DEBUG_S_LINES: 1 entries ( 56 bytes) +ALL-NEXT: DEBUG_S_FILECHKSMS: 1 entries ( 32 bytes) ALL-NEXT: Mod 0001 | `* Linker *`: ALL-NEXT: Stream 14, 520 bytes ALL: Symbols ALL-NEXT: Total: 13 entries ( 512 bytes) ALL-NEXT: -------------------------------------------------------------------------- -ALL-NEXT: S_SECTION: 4 entries ( 112 bytes) ALL-NEXT: S_ENVBLOCK: 1 entries ( 172 bytes) +ALL-NEXT: S_COFFGROUP: 5 entries ( 140 bytes) +ALL-NEXT: S_SECTION: 4 entries ( 112 bytes) +ALL-NEXT: S_COMPILE3: 1 entries ( 48 bytes) ALL-NEXT: S_TRAMPOLINE: 1 entries ( 20 bytes) ALL-NEXT: S_OBJNAME: 1 entries ( 20 bytes) -ALL-NEXT: S_COMPILE3: 1 entries ( 48 bytes) -ALL-NEXT: S_COFFGROUP: 5 entries ( 140 bytes) ALL: Chunks ALL-NEXT: Total: 0 entries ( 0 bytes) ALL-NEXT: -------------------------------------------------------------------------- @@ -35,21 +35,21 @@ ALL-NEXT: Summary | ALL: Symbols ALL-NEXT: Total: 19 entries ( 716 bytes) ALL-NEXT: -------------------------------------------------------------------------- +ALL-NEXT: S_ENVBLOCK: 1 entries ( 172 bytes) +ALL-NEXT: S_COFFGROUP: 5 entries ( 140 bytes) ALL-NEXT: S_SECTION: 4 entries ( 112 bytes) +ALL-NEXT: S_COMPILE3: 2 entries ( 108 bytes) +ALL-NEXT: S_OBJNAME: 2 entries ( 76 bytes) ALL-NEXT: S_GPROC32: 1 entries ( 44 bytes) -ALL-NEXT: S_ENVBLOCK: 1 entries ( 172 bytes) ALL-NEXT: S_FRAMEPROC: 1 entries ( 32 bytes) ALL-NEXT: S_TRAMPOLINE: 1 entries ( 20 bytes) -ALL-NEXT: S_END: 1 entries ( 4 bytes) -ALL-NEXT: S_OBJNAME: 2 entries ( 76 bytes) -ALL-NEXT: S_COMPILE3: 2 entries ( 108 bytes) -ALL-NEXT: S_COFFGROUP: 5 entries ( 140 bytes) ALL-NEXT: S_BUILDINFO: 1 entries ( 8 bytes) +ALL-NEXT: S_END: 1 entries ( 4 bytes) ALL: Chunks ALL-NEXT: Total: 2 entries ( 88 bytes) ALL-NEXT: -------------------------------------------------------------------------- -ALL-NEXT: DEBUG_S_FILECHKSMS: 1 entries ( 32 bytes) ALL-NEXT: DEBUG_S_LINES: 1 entries ( 56 bytes) +ALL-NEXT: DEBUG_S_FILECHKSMS: 1 entries ( 32 bytes) ONE-NOT: Mod 0000 ONE: Mod 0001 | `* Linker *`: @@ -57,12 +57,12 @@ ONE-NEXT: Stream 14, 520 bytes ONE: Symbols ONE-NEXT: Total: 13 entries ( 512 bytes) ONE-NEXT: -------------------------------------------------------------------------- -ONE-NEXT: S_SECTION: 4 entries ( 112 bytes) ONE-NEXT: S_ENVBLOCK: 1 entries ( 172 bytes) +ONE-NEXT: S_COFFGROUP: 5 entries ( 140 bytes) +ONE-NEXT: S_SECTION: 4 entries ( 112 bytes) +ONE-NEXT: S_COMPILE3: 1 entries ( 48 bytes) ONE-NEXT: S_TRAMPOLINE: 1 entries ( 20 bytes) ONE-NEXT: S_OBJNAME: 1 entries ( 20 bytes) -ONE-NEXT: S_COMPILE3: 1 entries ( 48 bytes) -ONE-NEXT: S_COFFGROUP: 5 entries ( 140 bytes) ONE: Chunks ONE-NEXT: Total: 0 entries ( 0 bytes) ONE-NEXT: -------------------------------------------------------------------------- @@ -70,12 +70,12 @@ ONE-NEXT: Summary | ONE: Symbols ONE-NEXT: Total: 13 entries ( 512 bytes) ONE-NEXT: -------------------------------------------------------------------------- -ONE-NEXT: S_SECTION: 4 entries ( 112 bytes) ONE-NEXT: S_ENVBLOCK: 1 entries ( 172 bytes) +ONE-NEXT: S_COFFGROUP: 5 entries ( 140 bytes) +ONE-NEXT: S_SECTION: 4 entries ( 112 bytes) +ONE-NEXT: S_COMPILE3: 1 entries ( 48 bytes) ONE-NEXT: S_TRAMPOLINE: 1 entries ( 20 bytes) ONE-NEXT: S_OBJNAME: 1 entries ( 20 bytes) -ONE-NEXT: S_COMPILE3: 1 entries ( 48 bytes) -ONE-NEXT: S_COFFGROUP: 5 entries ( 140 bytes) ONE: Chunks ONE-NEXT: Total: 0 entries ( 0 bytes) ONE-NEXT: -------------------------------------------------------------------------- diff --git a/test/DebugInfo/PDB/type-stats.test b/test/DebugInfo/PDB/type-stats.test new file mode 100644 index 00000000000..1fff263a954 --- /dev/null +++ b/test/DebugInfo/PDB/type-stats.test @@ -0,0 +1,17 @@ +; RUN: llvm-pdbutil dump -type-stats %p/Inputs/empty.pdb | FileCheck --check-prefix=ALL %s + +ALL: Type Record Stats +ALL-NEXT: ============================================================ + +ALL: Types +ALL-NEXT: Total: 75 entries ( 5,336 bytes, 71.15 avg) +ALL-NEXT: -------------------------------------------------------------------------- +ALL-NEXT: LF_FIELDLIST: 14 entries ( 1,956 bytes, 139.71 avg) +ALL-NEXT: LF_STRUCTURE: 14 entries ( 1,584 bytes, 113.14 avg) +ALL-NEXT: LF_ENUM: 8 entries ( 988 bytes, 123.50 avg) +ALL-NEXT: LF_MFUNCTION: 14 entries ( 392 bytes, 28.00 avg) +ALL-NEXT: LF_ARGLIST: 10 entries ( 176 bytes, 17.60 avg) +ALL-NEXT: LF_METHODLIST: 5 entries ( 116 bytes, 23.20 avg) +ALL-NEXT: LF_POINTER: 8 entries ( 96 bytes, 12.00 avg) +ALL-NEXT: LF_PROCEDURE: 1 entries ( 16 bytes, 16.00 avg) +ALL-NEXT: LF_MODIFIER: 1 entries ( 12 bytes, 12.00 avg) diff --git a/test/DebugInfo/PDB/udt-stats.test b/test/DebugInfo/PDB/udt-stats.test index 0ffda9c3008..35bfad8f315 100644 --- a/test/DebugInfo/PDB/udt-stats.test +++ b/test/DebugInfo/PDB/udt-stats.test @@ -4,12 +4,12 @@ CHECK: S_UDT Record Stats CHECK-NEXT: ============================================================ CHECK: Record Kind | Count Size CHECK-NEXT: ----------------------------- -CHECK-NEXT: LF_ENUM | 3 188 +CHECK-NEXT: LF_STRUCTURE | 27 1,788 CHECK-NEXT: LF_POINTER | 39 468 +CHECK-NEXT: LF_ENUM | 3 188 CHECK-NEXT: LF_UNION | 1 52 -CHECK-NEXT: | 43 0 CHECK-NEXT: LF_PROCEDURE | 1 16 -CHECK-NEXT: LF_STRUCTURE | 27 1,788 +CHECK-NEXT: | 43 0 CHECK-NEXT: ----------------------------- CHECK-NEXT: Total (S_UDT) | 114 2,604 CHECK-NEXT: ----------------------------- diff --git a/tools/llvm-pdbutil/DumpOutputStyle.cpp b/tools/llvm-pdbutil/DumpOutputStyle.cpp index f3f25669fc5..28d93e8f7bb 100644 --- a/tools/llvm-pdbutil/DumpOutputStyle.cpp +++ b/tools/llvm-pdbutil/DumpOutputStyle.cpp @@ -110,6 +110,12 @@ Error DumpOutputStyle::dump() { P.NewLine(); } + if (opts::dump::DumpTypeStats) { + if (auto EC = dumpTypeStats()) + return EC; + P.NewLine(); + } + if (opts::dump::DumpNamedStreams) { if (auto EC = dumpNamedStreams()) return EC; @@ -307,18 +313,30 @@ static inline std::string formatModuleDetailKind(SymbolKind K) { return formatSymbolKind(K); } +// Get the stats sorted by size, descending. +std::vector +StatCollection::getStatsSortedBySize() const { + std::vector SortedStats(Individual.begin(), Individual.end()); + std::stable_sort(SortedStats.begin(), SortedStats.end(), + [](const KindAndStat &LHS, const KindAndStat &RHS) { + return LHS.second.Size > RHS.second.Size; + }); + return SortedStats; +} + template static void printModuleDetailStats(LinePrinter &P, StringRef Label, const StatCollection &Stats) { P.NewLine(); P.formatLine(" {0}", Label); AutoIndent Indent(P); - P.formatLine("{0,40}: {1,7} entries ({2,8} bytes)", "Total", + P.formatLine("{0,40}: {1,7} entries ({2,12:N} bytes)", "Total", Stats.Totals.Count, Stats.Totals.Size); P.formatLine("{0}", fmt_repeat('-', 74)); - for (const auto &K : Stats.Individual) { + + for (const auto &K : Stats.getStatsSortedBySize()) { std::string KindName = formatModuleDetailKind(Kind(K.first)); - P.formatLine("{0,40}: {1,7} entries ({2,8} bytes)", KindName, + P.formatLine("{0,40}: {1,7} entries ({2,12:N} bytes)", KindName, K.second.Count, K.second.Size); } } @@ -676,6 +694,35 @@ Error DumpOutputStyle::dumpSymbolStats() { return Error::success(); } +Error DumpOutputStyle::dumpTypeStats() { + printHeader(P, "Type Record Stats"); + + // Iterate the types, categorize by kind, accumulate size stats. + StatCollection TypeStats; + LazyRandomTypeCollection &Types = File.types(); + for (Optional TI = Types.getFirst(); TI; TI = Types.getNext(*TI)) { + CVType Type = Types.getType(*TI); + TypeStats.update(uint32_t(Type.kind()), Type.length()); + } + + P.NewLine(); + P.formatLine(" Types"); + AutoIndent Indent(P); + P.formatLine("{0,14}: {1,7} entries ({2,12:N} bytes, {3,7} avg)", "Total", + TypeStats.Totals.Count, TypeStats.Totals.Size, + (double)TypeStats.Totals.Size / TypeStats.Totals.Count); + P.formatLine("{0}", fmt_repeat('-', 74)); + + for (const auto &K : TypeStats.getStatsSortedBySize()) { + P.formatLine("{0,14}: {1,7} entries ({2,12:N} bytes, {3,7} avg)", + formatTypeLeafKind(TypeLeafKind(K.first)), K.second.Count, + K.second.Size, (double)K.second.Size / K.second.Count); + } + + + return Error::success(); +} + static bool isValidNamespaceIdentifier(StringRef S) { if (S.empty()) return false; @@ -820,7 +867,7 @@ Error DumpOutputStyle::dumpUdtStats() { fmt_align(SizeHeader, AlignStyle::Right, SD)); P.formatLine("{0}", fmt_repeat('-', TableWidth)); - for (const auto &Stat : UdtTargetStats.Individual) { + for (const auto &Stat : UdtTargetStats.getStatsSortedBySize()) { StringRef Label = getUdtStatLabel(Stat.first); P.formatLine("{0} | {1:N} {2:N}", fmt_align(Label, AlignStyle::Right, FieldWidth), @@ -833,12 +880,25 @@ Error DumpOutputStyle::dumpUdtStats() { fmt_align(UdtStats.Totals.Count, AlignStyle::Right, CD), fmt_align(UdtStats.Totals.Size, AlignStyle::Right, SD)); P.formatLine("{0}", fmt_repeat('-', TableWidth)); - for (const auto &Stat : NamespacedStats) { - std::string Label = formatv("namespace '{0}'", Stat.getKey()); + struct StrAndStat { + StringRef Key; + StatCollection::Stat Stat; + }; + + // Print namespace stats in descending order of size. + std::vector NamespacedStatsSorted; + for (const auto &Stat : NamespacedStats) + NamespacedStatsSorted.push_back({Stat.getKey(), Stat.second}); + std::stable_sort(NamespacedStatsSorted.begin(), NamespacedStatsSorted.end(), + [](const StrAndStat &L, const StrAndStat &R) { + return L.Stat.Size > R.Stat.Size; + }); + for (const auto &Stat : NamespacedStatsSorted) { + std::string Label = formatv("namespace '{0}'", Stat.Key); P.formatLine("{0} | {1:N} {2:N}", fmt_align(Label, AlignStyle::Right, FieldWidth), - fmt_align(Stat.second.Count, AlignStyle::Right, CD), - fmt_align(Stat.second.Size, AlignStyle::Right, SD)); + fmt_align(Stat.Stat.Count, AlignStyle::Right, CD), + fmt_align(Stat.Stat.Size, AlignStyle::Right, SD)); } return Error::success(); } diff --git a/tools/llvm-pdbutil/DumpOutputStyle.h b/tools/llvm-pdbutil/DumpOutputStyle.h index a55522389a7..796cd7a10c3 100644 --- a/tools/llvm-pdbutil/DumpOutputStyle.h +++ b/tools/llvm-pdbutil/DumpOutputStyle.h @@ -49,6 +49,8 @@ struct StatCollection { } }; + using KindAndStat = std::pair; + void update(uint32_t Kind, uint32_t RecordSize) { Totals.update(RecordSize); auto Iter = Individual.try_emplace(Kind, 1, RecordSize); @@ -57,6 +59,8 @@ struct StatCollection { } Stat Totals; DenseMap Individual; + + std::vector getStatsSortedBySize() const; }; class DumpOutputStyle : public OutputStyle { @@ -78,6 +82,7 @@ private: Error dumpStreamSummary(); Error dumpSymbolStats(); Error dumpUdtStats(); + Error dumpTypeStats(); Error dumpNamedStreams(); Error dumpStringTable(); Error dumpStringTableFromPdb(); diff --git a/tools/llvm-pdbutil/llvm-pdbutil.cpp b/tools/llvm-pdbutil/llvm-pdbutil.cpp index 8a2a6f8194b..43a4259cf38 100644 --- a/tools/llvm-pdbutil/llvm-pdbutil.cpp +++ b/tools/llvm-pdbutil/llvm-pdbutil.cpp @@ -462,7 +462,10 @@ cl::opt DumpSymbolStats( "sym-stats", cl::desc("Dump a detailed breakdown of symbol usage/size for each module"), cl::cat(MsfOptions), cl::sub(DumpSubcommand)); - +cl::opt DumpTypeStats( + "type-stats", + cl::desc("Dump a detailed breakdown of type usage/size"), + cl::cat(MsfOptions), cl::sub(DumpSubcommand)); cl::opt DumpUdtStats( "udt-stats", cl::desc("Dump a detailed breakdown of S_UDT record usage / stats"), diff --git a/tools/llvm-pdbutil/llvm-pdbutil.h b/tools/llvm-pdbutil/llvm-pdbutil.h index 1b98d5230e4..321f41bba7f 100644 --- a/tools/llvm-pdbutil/llvm-pdbutil.h +++ b/tools/llvm-pdbutil/llvm-pdbutil.h @@ -140,6 +140,7 @@ extern llvm::cl::opt DumpSummary; extern llvm::cl::opt DumpFpm; extern llvm::cl::opt DumpStreams; extern llvm::cl::opt DumpSymbolStats; +extern llvm::cl::opt DumpTypeStats; extern llvm::cl::opt DumpUdtStats; extern llvm::cl::opt DumpStreamBlocks; -- 2.11.0