diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 20:50:12 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 20:50:12 +0000 |
commit | e6d1592492a3a379186bfb02bd0f4eda0669c0d5 (patch) | |
tree | 599ab169a01f1c86eda9adc774edaedde2f2db5b /tools/llvm-pdbutil/DumpOutputStyle.cpp | |
parent | 1a56a5ead7a2e84bee8240f5f6b033b5f1707154 (diff) |
Diffstat (limited to 'tools/llvm-pdbutil/DumpOutputStyle.cpp')
-rw-r--r-- | tools/llvm-pdbutil/DumpOutputStyle.cpp | 192 |
1 files changed, 152 insertions, 40 deletions
diff --git a/tools/llvm-pdbutil/DumpOutputStyle.cpp b/tools/llvm-pdbutil/DumpOutputStyle.cpp index e4f6aa7f6ec5..962d4cf88a8a 100644 --- a/tools/llvm-pdbutil/DumpOutputStyle.cpp +++ b/tools/llvm-pdbutil/DumpOutputStyle.cpp @@ -1,9 +1,8 @@ //===- DumpOutputStyle.cpp ------------------------------------ *- C++ --*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// @@ -14,6 +13,7 @@ #include "MinimalSymbolDumper.h" #include "MinimalTypeDumper.h" #include "StreamUtil.h" +#include "TypeReferenceTracker.h" #include "llvm-pdbutil.h" #include "llvm/ADT/STLExtras.h" @@ -61,7 +61,12 @@ using namespace llvm::msf; using namespace llvm::pdb; DumpOutputStyle::DumpOutputStyle(InputFile &File) - : File(File), P(2, false, outs()) {} + : File(File), P(2, false, outs()) { + if (opts::dump::DumpTypeRefStats) + RefTracker.reset(new TypeReferenceTracker(File)); +} + +DumpOutputStyle::~DumpOutputStyle() {} PDBFile &DumpOutputStyle::getPdb() { return File.pdb(); } object::COFFObjectFile &DumpOutputStyle::getObj() { return File.obj(); } @@ -77,6 +82,10 @@ void DumpOutputStyle::printStreamNotPresent(StringRef StreamName) { } Error DumpOutputStyle::dump() { + // Walk symbols & globals if we are supposed to mark types referenced. + if (opts::dump::DumpTypeRefStats) + RefTracker->mark(); + if (opts::dump::DumpSummary) { if (auto EC = dumpFileSummary()) return EC; @@ -101,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; @@ -188,6 +203,11 @@ Error DumpOutputStyle::dump() { return EC; } + if (opts::dump::DumpTypeRefStats) { + if (auto EC = dumpTypeRefStats()) + return EC; + } + if (opts::dump::DumpSectionHeaders) { if (auto EC = dumpSectionHeaders()) return EC; @@ -203,6 +223,8 @@ Error DumpOutputStyle::dump() { return EC; } + P.NewLine(); + return Error::success(); } @@ -293,18 +315,30 @@ static inline std::string formatModuleDetailKind(SymbolKind K) { 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()); + llvm::stable_sort(SortedStats, + [](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); } } @@ -662,6 +696,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<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; @@ -806,7 +869,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), @@ -819,12 +882,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<StrAndStat> NamespacedStatsSorted; + for (const auto &Stat : NamespacedStats) + NamespacedStatsSorted.push_back({Stat.getKey(), Stat.second}); + llvm::stable_sort(NamespacedStatsSorted, + [](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(); } @@ -921,6 +997,10 @@ Error DumpOutputStyle::dumpInlineeLines() { P.formatLine("{0,+8} | {1,+5} | ", Entry.Header->Inlinee, fmtle(Entry.Header->SourceLineNum)); Strings.formatFromChecksumsOffset(P, Entry.Header->FileID, true); + for (const auto &ExtraFileID : Entry.ExtraFiles) { + P.formatLine(" "); + Strings.formatFromChecksumsOffset(P, ExtraFileID, true); + } } P.NewLine(); }); @@ -1011,17 +1091,12 @@ Error DumpOutputStyle::dumpOldFpo(PDBFile &File) { ExitOnError Err("Error dumping old fpo data:"); auto &Dbi = Err(File.getPDBDbiStream()); - uint32_t Index = Dbi.getDebugStreamIndex(DbgHeaderType::FPO); - if (Index == kInvalidStreamIndex) { + if (!Dbi.hasOldFpoRecords()) { printStreamNotPresent("FPO"); return Error::success(); } - std::unique_ptr<MappedBlockStream> OldFpo = File.createIndexedStream(Index); - BinaryStreamReader Reader(*OldFpo); - FixedStreamArray<object::FpoData> Records; - Err(Reader.readArray(Records, - Reader.bytesRemaining() / sizeof(object::FpoData))); + const FixedStreamArray<object::FpoData>& Records = Dbi.getOldFpoRecords(); P.printLine(" RVA | Code | Locals | Params | Prolog | Saved Regs | Use " "BP | Has SEH | Frame Type"); @@ -1043,18 +1118,12 @@ Error DumpOutputStyle::dumpNewFpo(PDBFile &File) { ExitOnError Err("Error dumping new fpo data:"); auto &Dbi = Err(File.getPDBDbiStream()); - uint32_t Index = Dbi.getDebugStreamIndex(DbgHeaderType::NewFPO); - if (Index == kInvalidStreamIndex) { + if (!Dbi.hasNewFpoRecords()) { printStreamNotPresent("New FPO"); return Error::success(); } - std::unique_ptr<MappedBlockStream> NewFpo = File.createIndexedStream(Index); - - DebugFrameDataSubsectionRef FDS; - if (auto EC = FDS.initialize(*NewFpo)) - return make_error<RawError>(raw_error_code::corrupt_file, - "Invalid new fpo stream"); + const DebugFrameDataSubsectionRef& FDS = Dbi.getNewFpoRecords(); P.printLine(" RVA | Code | Locals | Params | Stack | Prolog | Saved Regs " "| Has SEH | Has C++EH | Start | Program"); @@ -1239,14 +1308,15 @@ static void buildDepSet(LazyRandomTypeCollection &Types, static void dumpFullTypeStream(LinePrinter &Printer, LazyRandomTypeCollection &Types, - uint32_t NumTypeRecords, uint32_t NumHashBuckets, + TypeReferenceTracker *RefTracker, uint32_t NumTypeRecords, + uint32_t NumHashBuckets, FixedStreamArray<support::ulittle32_t> HashValues, TpiStream *Stream, bool Bytes, bool Extras) { Printer.formatLine("Showing {0:N} records", NumTypeRecords); uint32_t Width = NumDigits(TypeIndex::FirstNonSimpleIndex + NumTypeRecords); - MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types, + MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types, RefTracker, NumHashBuckets, HashValues, Stream); if (auto EC = codeview::visitTypeStream(Types, V)) { @@ -1257,12 +1327,13 @@ dumpFullTypeStream(LinePrinter &Printer, LazyRandomTypeCollection &Types, static void dumpPartialTypeStream(LinePrinter &Printer, LazyRandomTypeCollection &Types, + TypeReferenceTracker *RefTracker, TpiStream &Stream, ArrayRef<TypeIndex> TiList, bool Bytes, bool Extras, bool Deps) { uint32_t Width = NumDigits(TypeIndex::FirstNonSimpleIndex + Stream.getNumTypeRecords()); - MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types, + MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types, RefTracker, Stream.getNumHashBuckets(), Stream.getHashValues(), &Stream); @@ -1311,12 +1382,12 @@ Error DumpOutputStyle::dumpTypesFromObjectFile() { else continue; - StringRef Contents; - if (auto EC = S.getContents(Contents)) - return errorCodeToError(EC); + Expected<StringRef> ContentsOrErr = S.getContents(); + if (!ContentsOrErr) + return ContentsOrErr.takeError(); uint32_t Magic; - BinaryStreamReader Reader(Contents, llvm::support::little); + BinaryStreamReader Reader(*ContentsOrErr, llvm::support::little); if (auto EC = Reader.readInteger(Magic)) return EC; if (Magic != COFF::DEBUG_SECTION_MAGIC) @@ -1326,8 +1397,8 @@ Error DumpOutputStyle::dumpTypesFromObjectFile() { Types.reset(Reader, 100); if (opts::dump::DumpTypes) { - dumpFullTypeStream(P, Types, 0, 0, {}, nullptr, opts::dump::DumpTypeData, - false); + dumpFullTypeStream(P, Types, RefTracker.get(), 0, 0, {}, nullptr, + opts::dump::DumpTypeData, false); } else if (opts::dump::DumpTypeExtras) { auto LocalHashes = LocallyHashedType::hashTypeCollection(Types); auto GlobalHashes = GloballyHashedType::hashTypeCollection(Types); @@ -1396,23 +1467,36 @@ Error DumpOutputStyle::dumpTpiStream(uint32_t StreamIdx) { auto &Types = (StreamIdx == StreamTPI) ? File.types() : File.ids(); + // Only emit notes about referenced/unreferenced for types. + TypeReferenceTracker *MaybeTracker = + (StreamIdx == StreamTPI) ? RefTracker.get() : nullptr; + // Enable resolving forward decls. Stream.buildHashMap(); if (DumpTypes || !Indices.empty()) { if (Indices.empty()) - dumpFullTypeStream(P, Types, Stream.getNumTypeRecords(), + dumpFullTypeStream(P, Types, MaybeTracker, Stream.getNumTypeRecords(), Stream.getNumHashBuckets(), Stream.getHashValues(), &Stream, DumpBytes, DumpExtras); else { std::vector<TypeIndex> TiList(Indices.begin(), Indices.end()); - dumpPartialTypeStream(P, Types, Stream, TiList, DumpBytes, DumpExtras, - opts::dump::DumpTypeDependents); + dumpPartialTypeStream(P, Types, MaybeTracker, Stream, TiList, DumpBytes, + DumpExtras, opts::dump::DumpTypeDependents); } } if (DumpExtras) { P.NewLine(); + + P.formatLine("Header Version: {0}", + static_cast<uint32_t>(Stream.getTpiVersion())); + P.formatLine("Hash Stream Index: {0}", Stream.getTypeHashStreamIndex()); + P.formatLine("Aux Hash Stream Index: {0}", + Stream.getTypeHashStreamAuxIndex()); + P.formatLine("Hash Key Size: {0}", Stream.getHashKeySize()); + P.formatLine("Num Hash Buckets: {0}", Stream.getNumHashBuckets()); + auto IndexOffsets = Stream.getTypeIndexOffsets(); P.formatLine("Type Index Offsets:"); for (const auto &IO : IndexOffsets) { @@ -1523,6 +1607,34 @@ Error DumpOutputStyle::dumpModuleSymsForPdb() { return Error::success(); } +Error DumpOutputStyle::dumpTypeRefStats() { + printHeader(P, "Type Reference Statistics"); + AutoIndent Indent(P); + + // Sum the byte size of all type records, and the size and count of all + // referenced records. + size_t TotalRecs = File.types().size(); + size_t RefRecs = 0; + size_t TotalBytes = 0; + size_t RefBytes = 0; + auto &Types = File.types(); + for (Optional<TypeIndex> TI = Types.getFirst(); TI; TI = Types.getNext(*TI)) { + CVType Type = File.types().getType(*TI); + TotalBytes += Type.length(); + if (RefTracker->isTypeReferenced(*TI)) { + ++RefRecs; + RefBytes += Type.length(); + } + } + + P.formatLine("Records referenced: {0:N} / {1:N} {2:P}", RefRecs, TotalRecs, + (double)RefRecs / TotalRecs); + P.formatLine("Bytes referenced: {0:N} / {1:N} {2:P}", RefBytes, TotalBytes, + (double)RefBytes / TotalBytes); + + return Error::success(); +} + Error DumpOutputStyle::dumpGSIRecords() { printHeader(P, "GSI Records"); |