diff options
Diffstat (limited to 'llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp')
| -rw-r--r-- | llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp | 161 |
1 files changed, 158 insertions, 3 deletions
diff --git a/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp b/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp index c573f606786..09424bd3df9 100644 --- a/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp +++ b/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp @@ -59,6 +59,7 @@ #include "llvm/Support/FormatAdapters.h" #include "llvm/Support/FormatVariadic.h" +#include <cctype> #include <unordered_map> using namespace llvm; @@ -82,8 +83,14 @@ Error DumpOutputStyle::dump() { P.NewLine(); } - if (opts::dump::DumpModuleStats.getNumOccurrences() > 0) { - if (auto EC = dumpModuleStats()) + if (opts::dump::DumpSymbolStats.getNumOccurrences() > 0) { + if (auto EC = dumpSymbolStats()) + return EC; + P.NewLine(); + } + + if (opts::dump::DumpUdtStats.getNumOccurrences() > 0) { + if (auto EC = dumpUdtStats()) return EC; P.NewLine(); } @@ -557,7 +564,7 @@ Error DumpOutputStyle::dumpModuleFiles() { return Error::success(); } -Error DumpOutputStyle::dumpModuleStats() { +Error DumpOutputStyle::dumpSymbolStats() { printHeader(P, "Module Stats"); ExitOnError Err("Unexpected error processing modules: "); @@ -607,6 +614,154 @@ Error DumpOutputStyle::dumpModuleStats() { return Error::success(); } +static bool isValidNamespaceIdentifier(StringRef S) { + if (S.empty()) + return false; + + if (std::isdigit(S[0])) + return false; + + return llvm::all_of(S, [](char C) { return std::isalnum(C); }); +} + +namespace { +constexpr uint32_t kNoneUdtKind = 0; +constexpr uint32_t kSimpleUdtKind = 1; +constexpr uint32_t kUnknownUdtKind = 2; +const StringRef NoneLabel("<none type>"); +const StringRef SimpleLabel("<simple type>"); +const StringRef UnknownLabel("<unknown type>"); + +} // namespace + +static StringRef getUdtStatLabel(uint32_t Kind) { + if (Kind == kNoneUdtKind) + return NoneLabel; + + if (Kind == kSimpleUdtKind) + return SimpleLabel; + + if (Kind == kUnknownUdtKind) + return UnknownLabel; + + return formatTypeLeafKind(static_cast<TypeLeafKind>(Kind)); +} + +static uint32_t getLongestTypeLeafName(const StatCollection &Stats) { + size_t L = 0; + for (const auto &Stat : Stats.Individual) { + StringRef Label = getUdtStatLabel(Stat.first); + L = std::max(L, Label.size()); + } + return static_cast<uint32_t>(L); +} + +Error DumpOutputStyle::dumpUdtStats() { + printHeader(P, "S_UDT Record Stats"); + + StatCollection UdtStats; + StatCollection UdtTargetStats; + if (!File.hasPDBGlobalsStream()) { + P.printLine("- Error: globals stream not present"); + return Error::success(); + } + + AutoIndent Indent(P, 4); + + auto &SymbolRecords = cantFail(File.getPDBSymbolStream()); + auto &Globals = cantFail(File.getPDBGlobalsStream()); + auto &TpiTypes = cantFail(initializeTypes(StreamTPI)); + + StringMap<StatCollection::Stat> NamespacedStats; + + P.NewLine(); + + size_t LongestNamespace = 0; + for (uint32_t PubSymOff : Globals.getGlobalsTable()) { + CVSymbol Sym = SymbolRecords.readRecord(PubSymOff); + if (Sym.kind() != SymbolKind::S_UDT) + continue; + UdtStats.update(SymbolKind::S_UDT, Sym.length()); + + UDTSym UDT = cantFail(SymbolDeserializer::deserializeAs<UDTSym>(Sym)); + + uint32_t Kind = 0; + uint32_t RecordSize = 0; + if (UDT.Type.isSimple() || + (UDT.Type.toArrayIndex() >= TpiTypes.capacity())) { + if (UDT.Type.isNoneType()) + Kind = kNoneUdtKind; + else if (UDT.Type.isSimple()) + Kind = kSimpleUdtKind; + else + Kind = kUnknownUdtKind; + } else { + CVType T = TpiTypes.getType(UDT.Type); + Kind = T.kind(); + RecordSize = T.length(); + } + + UdtTargetStats.update(Kind, RecordSize); + + size_t Pos = UDT.Name.find("::"); + if (Pos == StringRef::npos) + continue; + + StringRef Scope = UDT.Name.take_front(Pos); + if (Scope.empty() || !isValidNamespaceIdentifier(Scope)) + continue; + + LongestNamespace = std::max(LongestNamespace, Scope.size()); + NamespacedStats[Scope].update(RecordSize); + } + + LongestNamespace += StringRef(" namespace ''").size(); + uint32_t LongestTypeLeafKind = getLongestTypeLeafName(UdtTargetStats); + uint32_t FieldWidth = std::max(LongestNamespace, LongestTypeLeafKind); + + // Compute the max number of digits for count and size fields, including comma + // separators. + StringRef CountHeader("Count"); + StringRef SizeHeader("Size"); + uint32_t CD = NumDigits(UdtStats.Totals.Count); + CD += (CD - 1) / 3; + CD = std::max(CD, CountHeader.size()); + + uint32_t SD = NumDigits(UdtStats.Totals.Size); + SD += (SD - 1) / 3; + SD = std::max(SD, SizeHeader.size()); + + uint32_t TableWidth = FieldWidth + 3 + CD + 2 + SD + 1; + + P.formatLine("{0} | {1} {2}", + fmt_align("Record Kind", AlignStyle::Right, FieldWidth), + fmt_align(CountHeader, AlignStyle::Right, CD), + fmt_align(SizeHeader, AlignStyle::Right, SD)); + + P.formatLine("{0}", fmt_repeat('-', TableWidth)); + for (const auto &Stat : UdtTargetStats.Individual) { + StringRef Label = getUdtStatLabel(Stat.first); + 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)); + } + P.formatLine("{0}", fmt_repeat('-', TableWidth)); + P.formatLine("{0} | {1:N} {2:N}", + fmt_align("Total (S_UDT)", 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()); + 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)); + } + return Error::success(); +} + static void typesetLinesAndColumns(PDBFile &File, LinePrinter &P, uint32_t Start, const LineColumnEntry &E) { const uint32_t kMaxCharsPerLineNumber = 4; // 4 digit line number |

