Speed up iteration of CodeView record streams.
authorZachary Turner <zturner@google.com>
Thu, 18 Jan 2018 18:35:01 +0000 (18:35 +0000)
committerZachary Turner <zturner@google.com>
Thu, 18 Jan 2018 18:35:01 +0000 (18:35 +0000)
There's some abstraction overhead in the underlying
mechanisms that were being used, and it was leading to an
abundance of small but not-free copies being made.  This
showed up on a profile.  Eliminating this and going back to
a low-level byte-based implementation speeds up lld with
/DEBUG between 10 and 15%.

Differential Revision: https://reviews.llvm.org/D42148

llvm-svn: 322871

lld/COFF/PDB.cpp
llvm/include/llvm/DebugInfo/CodeView/CVRecord.h
llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp

index 7c620e4..e8395c8 100644 (file)
@@ -677,54 +677,61 @@ static void mergeSymbolRecords(BumpPtrAllocator &Alloc, ObjFile *File,
                                BinaryStreamRef SymData) {
   // FIXME: Improve error recovery by warning and skipping records when
   // possible.
-  CVSymbolArray Syms;
-  BinaryStreamReader Reader(SymData);
-  ExitOnErr(Reader.readArray(Syms, Reader.getLength()));
+  ArrayRef<uint8_t> SymsBuffer;
+  cantFail(SymData.readBytes(0, SymData.getLength(), SymsBuffer));
   SmallVector<SymbolScope, 4> Scopes;
-  for (CVSymbol Sym : Syms) {
-    // Discover type index references in the record. Skip it if we don't know
-    // where they are.
-    SmallVector<TiReference, 32> TypeRefs;
-    if (!discoverTypeIndicesInSymbol(Sym, TypeRefs)) {
-      log("ignoring unknown symbol record with kind 0x" + utohexstr(Sym.kind()));
-      continue;
-    }
-
-    // Copy the symbol record so we can mutate it.
-    MutableArrayRef<uint8_t> NewData = copySymbolForPdb(Sym, Alloc);
-
-    // Re-map all the type index references.
-    MutableArrayRef<uint8_t> Contents =
-        NewData.drop_front(sizeof(RecordPrefix));
-    remapTypesInSymbolRecord(File, Sym.kind(), Contents, IndexMap, TypeRefs);
-
-    // An object file may have S_xxx_ID symbols, but these get converted to
-    // "real" symbols in a PDB.
-    translateIdSymbols(NewData, IDTable);
 
-    // If this record refers to an offset in the object file's string table,
-    // add that item to the global PDB string table and re-write the index.
-    recordStringTableReferences(Sym.kind(), Contents, StringTableRefs);
-
-    SymbolKind NewKind = symbolKind(NewData);
-
-    // Fill in "Parent" and "End" fields by maintaining a stack of scopes.
-    CVSymbol NewSym(NewKind, NewData);
-    if (symbolOpensScope(NewKind))
-      scopeStackOpen(Scopes, File->ModuleDBI->getNextSymbolOffset(), NewSym);
-    else if (symbolEndsScope(NewKind))
-      scopeStackClose(Scopes, File->ModuleDBI->getNextSymbolOffset(), File);
-
-    // Add the symbol to the globals stream if necessary.  Do this before adding
-    // the symbol to the module since we may need to get the next symbol offset,
-    // and writing to the module's symbol stream will update that offset.
-    if (symbolGoesInGlobalsStream(NewSym))
-      addGlobalSymbol(GsiBuilder, *File, NewSym);
+  auto EC = forEachCodeViewRecord<CVSymbol>(
+      SymsBuffer, [&](const CVSymbol &Sym) -> llvm::Error {
+        // Discover type index references in the record. Skip it if we don't
+        // know where they are.
+        SmallVector<TiReference, 32> TypeRefs;
+        if (!discoverTypeIndicesInSymbol(Sym, TypeRefs)) {
+          log("ignoring unknown symbol record with kind 0x" +
+              utohexstr(Sym.kind()));
+          return Error::success();
+        }
 
-    // Add the symbol to the module.
-    if (symbolGoesInModuleStream(NewSym))
-      File->ModuleDBI->addSymbol(NewSym);
-  }
+        // Copy the symbol record so we can mutate it.
+        MutableArrayRef<uint8_t> NewData = copySymbolForPdb(Sym, Alloc);
+
+        // Re-map all the type index references.
+        MutableArrayRef<uint8_t> Contents =
+            NewData.drop_front(sizeof(RecordPrefix));
+        remapTypesInSymbolRecord(File, Sym.kind(), Contents, IndexMap,
+                                 TypeRefs);
+
+        // An object file may have S_xxx_ID symbols, but these get converted to
+        // "real" symbols in a PDB.
+        translateIdSymbols(NewData, IDTable);
+
+        // If this record refers to an offset in the object file's string table,
+        // add that item to the global PDB string table and re-write the index.
+        recordStringTableReferences(Sym.kind(), Contents, StringTableRefs);
+
+        SymbolKind NewKind = symbolKind(NewData);
+
+        // Fill in "Parent" and "End" fields by maintaining a stack of scopes.
+        CVSymbol NewSym(NewKind, NewData);
+        if (symbolOpensScope(NewKind))
+          scopeStackOpen(Scopes, File->ModuleDBI->getNextSymbolOffset(),
+                         NewSym);
+        else if (symbolEndsScope(NewKind))
+          scopeStackClose(Scopes, File->ModuleDBI->getNextSymbolOffset(), File);
+
+        // Add the symbol to the globals stream if necessary.  Do this before
+        // adding the symbol to the module since we may need to get the next
+        // symbol offset, and writing to the module's symbol stream will update
+        // that offset.
+        if (symbolGoesInGlobalsStream(NewSym))
+          addGlobalSymbol(GsiBuilder, *File, NewSym);
+
+        // Add the symbol to the module.
+        if (symbolGoesInModuleStream(NewSym))
+          File->ModuleDBI->addSymbol(NewSym);
+        return Error::success();
+      });
+  cantFail(std::move(EC));
 }
 
 // Allocate memory for a .debug$S section and relocate it.
index 9f3a753..596996d 100644 (file)
@@ -61,6 +61,30 @@ template <typename Kind> struct RemappedRecord {
   SmallVector<std::pair<uint32_t, TypeIndex>, 8> Mappings;
 };
 
+template <typename Record, typename Func>
+Error forEachCodeViewRecord(ArrayRef<uint8_t> StreamBuffer, Func F) {
+  while (!StreamBuffer.empty()) {
+    if (StreamBuffer.size() < sizeof(RecordPrefix))
+      return make_error<CodeViewError>(cv_error_code::corrupt_record);
+
+    const RecordPrefix *Prefix =
+        reinterpret_cast<const RecordPrefix *>(StreamBuffer.data());
+
+    uint16_t RealLen = Prefix->RecordLen + 2;
+    if (StreamBuffer.size() < RealLen)
+      return make_error<CodeViewError>(cv_error_code::corrupt_record);
+
+    ArrayRef<uint8_t> Data = StreamBuffer.take_front(RealLen);
+    StreamBuffer = StreamBuffer.drop_front(RealLen);
+
+    Record R(static_cast<decltype(Record::Type)>((uint16_t)Prefix->RecordKind),
+             Data);
+    if (auto EC = F(R))
+      return EC;
+  }
+  return Error::success();
+}
+
 /// Read a complete record from a stream at a random offset.
 template <typename Kind>
 inline Expected<CVRecord<Kind>> readCVRecordFromStream(BinaryStreamRef Stream,
index 6a94952..f1ebd23 100644 (file)
@@ -346,10 +346,12 @@ Error TypeStreamMerger::doit(const CVTypeArray &Types) {
 }
 
 Error TypeStreamMerger::remapAllTypes(const CVTypeArray &Types) {
-  for (const CVType &Type : Types)
-    if (auto EC = remapType(Type))
-      return EC;
-  return Error::success();
+  BinaryStreamRef Stream = Types.getUnderlyingStream();
+  ArrayRef<uint8_t> Buffer;
+  cantFail(Stream.readBytes(0, Stream.getLength(), Buffer));
+
+  return forEachCodeViewRecord<CVType>(
+      Buffer, [this](const CVType &T) { return remapType(T); });
 }
 
 Error TypeStreamMerger::remapType(const CVType &Type) {