I tried to run llvm-pdbdump on a very large (~1.5GB) PDB to try and identify show-stopping performance problems. This patch addresses the first such problem. When loading the DBI stream, before anyone has even tried to access a single record, we build an in memory map of every source file for every module. In the particular PDB I was using, this was over 85 million files. Specifically, the complexity is O(m*n) where m is the number of modules and n is the average number of source files (including headers) per module. The whole reason for doing this was so that we could have constant time access to any module and any of its source file lists. However, we can still get O(1) access to the source file list for a given module with a simple O(m) precomputation, and access to the list of modules is already O(1) anyway. So this patches reduces the O(m*n) up-front precomputation to an O(m) one, where n is ~6,500 and n*m is about 85 million in my pathological test case. Differential Revision: https://reviews.llvm.org/D32870 llvm-svn: 302205
140 lines
4.9 KiB
C++
140 lines
4.9 KiB
C++
//===- StreamUtil.cpp - PDB stream utilities --------------------*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "StreamUtil.h"
|
|
|
|
#include "llvm/ADT/DenseMap.h"
|
|
#include "llvm/ADT/DenseMapInfo.h"
|
|
#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h"
|
|
#include "llvm/DebugInfo/PDB/Native/DbiModuleList.h"
|
|
#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
|
|
#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
|
|
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
|
|
#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
|
|
|
|
namespace llvm {
|
|
namespace pdb {
|
|
void discoverStreamPurposes(PDBFile &File,
|
|
SmallVectorImpl<std::string> &Purposes) {
|
|
|
|
// It's OK if we fail to load some of these streams, we still attempt to print
|
|
// what we can.
|
|
auto Dbi = File.getPDBDbiStream();
|
|
auto Tpi = File.getPDBTpiStream();
|
|
auto Ipi = File.getPDBIpiStream();
|
|
auto Info = File.getPDBInfoStream();
|
|
|
|
uint32_t StreamCount = File.getNumStreams();
|
|
DenseMap<uint16_t, DbiModuleDescriptor> ModStreams;
|
|
DenseMap<uint16_t, std::string> NamedStreams;
|
|
|
|
if (Dbi) {
|
|
const DbiModuleList &Modules = Dbi->modules();
|
|
for (uint32_t I = 0; I < Modules.getModuleCount(); ++I) {
|
|
DbiModuleDescriptor Descriptor = Modules.getModuleDescriptor(I);
|
|
uint16_t SN = Descriptor.getModuleStreamIndex();
|
|
if (SN != kInvalidStreamIndex)
|
|
ModStreams[SN] = Descriptor;
|
|
}
|
|
}
|
|
if (Info) {
|
|
for (auto &NSE : Info->named_streams()) {
|
|
if (NSE.second != kInvalidStreamIndex)
|
|
NamedStreams[NSE.second] = NSE.first();
|
|
}
|
|
}
|
|
|
|
Purposes.resize(StreamCount);
|
|
for (uint16_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) {
|
|
std::string Value;
|
|
if (StreamIdx == OldMSFDirectory)
|
|
Value = "Old MSF Directory";
|
|
else if (StreamIdx == StreamPDB)
|
|
Value = "PDB Stream";
|
|
else if (StreamIdx == StreamDBI)
|
|
Value = "DBI Stream";
|
|
else if (StreamIdx == StreamTPI)
|
|
Value = "TPI Stream";
|
|
else if (StreamIdx == StreamIPI)
|
|
Value = "IPI Stream";
|
|
else if (Dbi && StreamIdx == Dbi->getGlobalSymbolStreamIndex())
|
|
Value = "Global Symbol Hash";
|
|
else if (Dbi && StreamIdx == Dbi->getPublicSymbolStreamIndex())
|
|
Value = "Public Symbol Hash";
|
|
else if (Dbi && StreamIdx == Dbi->getSymRecordStreamIndex())
|
|
Value = "Public Symbol Records";
|
|
else if (Tpi && StreamIdx == Tpi->getTypeHashStreamIndex())
|
|
Value = "TPI Hash";
|
|
else if (Tpi && StreamIdx == Tpi->getTypeHashStreamAuxIndex())
|
|
Value = "TPI Aux Hash";
|
|
else if (Ipi && StreamIdx == Ipi->getTypeHashStreamIndex())
|
|
Value = "IPI Hash";
|
|
else if (Ipi && StreamIdx == Ipi->getTypeHashStreamAuxIndex())
|
|
Value = "IPI Aux Hash";
|
|
else if (Dbi &&
|
|
StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Exception))
|
|
Value = "Exception Data";
|
|
else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Fixup))
|
|
Value = "Fixup Data";
|
|
else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::FPO))
|
|
Value = "FPO Data";
|
|
else if (Dbi &&
|
|
StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::NewFPO))
|
|
Value = "New FPO Data";
|
|
else if (Dbi &&
|
|
StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::OmapFromSrc))
|
|
Value = "Omap From Source Data";
|
|
else if (Dbi &&
|
|
StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::OmapToSrc))
|
|
Value = "Omap To Source Data";
|
|
else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Pdata))
|
|
Value = "Pdata";
|
|
else if (Dbi &&
|
|
StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::SectionHdr))
|
|
Value = "Section Header Data";
|
|
else if (Dbi &&
|
|
StreamIdx ==
|
|
Dbi->getDebugStreamIndex(DbgHeaderType::SectionHdrOrig))
|
|
Value = "Section Header Original Data";
|
|
else if (Dbi &&
|
|
StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::TokenRidMap))
|
|
Value = "Token Rid Data";
|
|
else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Xdata))
|
|
Value = "Xdata";
|
|
else {
|
|
auto ModIter = ModStreams.find(StreamIdx);
|
|
auto NSIter = NamedStreams.find(StreamIdx);
|
|
if (ModIter != ModStreams.end()) {
|
|
Value = "Module \"";
|
|
Value += ModIter->second.getModuleName();
|
|
Value += "\"";
|
|
} else if (NSIter != NamedStreams.end()) {
|
|
Value = "Named Stream \"";
|
|
Value += NSIter->second;
|
|
Value += "\"";
|
|
} else {
|
|
Value = "???";
|
|
}
|
|
}
|
|
Purposes[StreamIdx] = Value;
|
|
}
|
|
|
|
// Consume errors from missing streams.
|
|
if (!Dbi)
|
|
consumeError(Dbi.takeError());
|
|
if (!Tpi)
|
|
consumeError(Tpi.takeError());
|
|
if (!Ipi)
|
|
consumeError(Ipi.takeError());
|
|
if (!Info)
|
|
consumeError(Info.takeError());
|
|
}
|
|
}
|
|
}
|