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: --------------------------------------------------------------------------
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 *`:
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: --------------------------------------------------------------------------
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: --------------------------------------------------------------------------
--- /dev/null
+; 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)
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: <simple type> | 43 0
CHECK-NEXT: LF_PROCEDURE | 1 16
-CHECK-NEXT: LF_STRUCTURE | 27 1,788
+CHECK-NEXT: <simple type> | 43 0
CHECK-NEXT: -----------------------------
CHECK-NEXT: Total (S_UDT) | 114 2,604
CHECK-NEXT: -----------------------------
P.NewLine();
}
+ if (opts::dump::DumpTypeStats) {
+ if (auto EC = dumpTypeStats())
+ return EC;
+ P.NewLine();
+ }
+
if (opts::dump::DumpNamedStreams) {
if (auto EC = dumpNamedStreams())
return EC;
return formatSymbolKind(K);
}
+// Get the stats sorted by size, descending.
+std::vector<StatCollection::KindAndStat>
+StatCollection::getStatsSortedBySize() const {
+ std::vector<KindAndStat> 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 <typename Kind>
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);
}
}
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<TypeIndex> 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;
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),
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<StrAndStat> 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();
}
}
};
+ using KindAndStat = std::pair<uint32_t, Stat>;
+
void update(uint32_t Kind, uint32_t RecordSize) {
Totals.update(RecordSize);
auto Iter = Individual.try_emplace(Kind, 1, RecordSize);
}
Stat Totals;
DenseMap<uint32_t, Stat> Individual;
+
+ std::vector<KindAndStat> getStatsSortedBySize() const;
};
class DumpOutputStyle : public OutputStyle {
Error dumpStreamSummary();
Error dumpSymbolStats();
Error dumpUdtStats();
+ Error dumpTypeStats();
Error dumpNamedStreams();
Error dumpStringTable();
Error dumpStringTableFromPdb();
"sym-stats",
cl::desc("Dump a detailed breakdown of symbol usage/size for each module"),
cl::cat(MsfOptions), cl::sub(DumpSubcommand));
-
+cl::opt<bool> DumpTypeStats(
+ "type-stats",
+ cl::desc("Dump a detailed breakdown of type usage/size"),
+ cl::cat(MsfOptions), cl::sub(DumpSubcommand));
cl::opt<bool> DumpUdtStats(
"udt-stats",
cl::desc("Dump a detailed breakdown of S_UDT record usage / stats"),
extern llvm::cl::opt<bool> DumpFpm;
extern llvm::cl::opt<bool> DumpStreams;
extern llvm::cl::opt<bool> DumpSymbolStats;
+extern llvm::cl::opt<bool> DumpTypeStats;
extern llvm::cl::opt<bool> DumpUdtStats;
extern llvm::cl::opt<bool> DumpStreamBlocks;