[llvm] r323790 - [CodeView] Micro-optimizations to speed up type merging.

Zachary Turner via llvm-commits llvm-commits at lists.llvm.org
Tue Jan 30 09:12:04 PST 2018


Author: zturner
Date: Tue Jan 30 09:12:04 2018
New Revision: 323790

URL: http://llvm.org/viewvc/llvm-project?rev=323790&view=rev
Log:
[CodeView] Micro-optimizations to speed up type merging.

Based on a profile, a couple of hot spots were identified in the
main type merging loop.  The code was simplified, a few loops
were re-arranged, and some outlined functions were inlined.  This
speeds up type merging by a decent amount, shaving around 3-4 seconds
off of a 40 second link in my test case.

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

Modified:
    llvm/trunk/include/llvm/DebugInfo/CodeView/CVRecord.h
    llvm/trunk/include/llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h
    llvm/trunk/lib/DebugInfo/CodeView/GlobalTypeTableBuilder.cpp
    llvm/trunk/lib/DebugInfo/CodeView/TypeStreamMerger.cpp

Modified: llvm/trunk/include/llvm/DebugInfo/CodeView/CVRecord.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/CodeView/CVRecord.h?rev=323790&r1=323789&r2=323790&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/CodeView/CVRecord.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/CodeView/CVRecord.h Tue Jan 30 09:12:04 2018
@@ -70,7 +70,7 @@ Error forEachCodeViewRecord(ArrayRef<uin
     const RecordPrefix *Prefix =
         reinterpret_cast<const RecordPrefix *>(StreamBuffer.data());
 
-    uint16_t RealLen = Prefix->RecordLen + 2;
+    size_t RealLen = Prefix->RecordLen + 2;
     if (StreamBuffer.size() < RealLen)
       return make_error<CodeViewError>(cv_error_code::corrupt_record);
 

Modified: llvm/trunk/include/llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h?rev=323790&r1=323789&r2=323790&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h Tue Jan 30 09:12:04 2018
@@ -69,9 +69,22 @@ public:
   ArrayRef<ArrayRef<uint8_t>> records() const;
   ArrayRef<GloballyHashedType> hashes() const;
 
-  using CreateRecord = llvm::function_ref<ArrayRef<uint8_t>()>;
+  template <typename CreateFunc>
+  TypeIndex insertRecordAs(GloballyHashedType Hash, size_t RecordSize,
+                           CreateFunc Create) {
+    auto Result = HashedRecords.try_emplace(Hash, nextTypeIndex());
+
+    if (LLVM_UNLIKELY(Result.second)) {
+      uint8_t *Stable = RecordStorage.Allocate<uint8_t>(RecordSize);
+      MutableArrayRef<uint8_t> Data(Stable, RecordSize);
+      SeenRecords.push_back(Create(Data));
+      SeenHashes.push_back(Hash);
+    }
+
+    // Update the caller's copy of Record to point a stable copy.
+    return Result.first->second;
+  }
 
-  TypeIndex insertRecordAs(GloballyHashedType Hash, CreateRecord Create);
   TypeIndex insertRecordBytes(ArrayRef<uint8_t> Data);
   TypeIndex insertRecord(ContinuationRecordBuilder &Builder);
 

Modified: llvm/trunk/lib/DebugInfo/CodeView/GlobalTypeTableBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/CodeView/GlobalTypeTableBuilder.cpp?rev=323790&r1=323789&r2=323790&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/CodeView/GlobalTypeTableBuilder.cpp (original)
+++ llvm/trunk/lib/DebugInfo/CodeView/GlobalTypeTableBuilder.cpp Tue Jan 30 09:12:04 2018
@@ -55,9 +55,12 @@ Optional<TypeIndex> GlobalTypeTableBuild
 CVType GlobalTypeTableBuilder::getType(TypeIndex Index) {
   CVType Type;
   Type.RecordData = SeenRecords[Index.toArrayIndex()];
-  const RecordPrefix *P =
-      reinterpret_cast<const RecordPrefix *>(Type.RecordData.data());
-  Type.Type = static_cast<TypeLeafKind>(uint16_t(P->RecordKind));
+  if (!Type.RecordData.empty()) {
+    assert(Type.RecordData.size() >= sizeof(RecordPrefix));
+    const RecordPrefix *P =
+        reinterpret_cast<const RecordPrefix *>(Type.RecordData.data());
+    Type.Type = static_cast<TypeLeafKind>(uint16_t(P->RecordKind));
+  }
   return Type;
 }
 
@@ -89,31 +92,15 @@ void GlobalTypeTableBuilder::reset() {
   SeenRecords.clear();
 }
 
-static inline ArrayRef<uint8_t> stabilize(BumpPtrAllocator &Alloc,
-                                          ArrayRef<uint8_t> Data) {
-  uint8_t *Stable = Alloc.Allocate<uint8_t>(Data.size());
-  memcpy(Stable, Data.data(), Data.size());
-  return makeArrayRef(Stable, Data.size());
-}
-
-TypeIndex GlobalTypeTableBuilder::insertRecordAs(GloballyHashedType Hash,
-                                                 CreateRecord Create) {
-  auto Result = HashedRecords.try_emplace(Hash, nextTypeIndex());
-
-  if (Result.second) {
-    ArrayRef<uint8_t> RecordData = stabilize(RecordStorage, Create());
-    SeenRecords.push_back(RecordData);
-    SeenHashes.push_back(Hash);
-  }
-
-  // Update the caller's copy of Record to point a stable copy.
-  return Result.first->second;
-}
-
 TypeIndex GlobalTypeTableBuilder::insertRecordBytes(ArrayRef<uint8_t> Record) {
   GloballyHashedType GHT =
       GloballyHashedType::hashType(Record, SeenHashes, SeenHashes);
-  return insertRecordAs(GHT, [Record]() { return Record; });
+  return insertRecordAs(GHT, Record.size(),
+                        [Record](MutableArrayRef<uint8_t> Data) {
+                          assert(Data.size() == Record.size());
+                          ::memcpy(Data.data(), Record.data(), Record.size());
+                          return Data;
+                        });
 }
 
 TypeIndex

Modified: llvm/trunk/lib/DebugInfo/CodeView/TypeStreamMerger.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/CodeView/TypeStreamMerger.cpp?rev=323790&r1=323789&r2=323790&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/CodeView/TypeStreamMerger.cpp (original)
+++ llvm/trunk/lib/DebugInfo/CodeView/TypeStreamMerger.cpp Tue Jan 30 09:12:04 2018
@@ -20,6 +20,11 @@
 using namespace llvm;
 using namespace llvm::codeview;
 
+static inline size_t slotForIndex(TypeIndex Idx) {
+  assert(!Idx.isSimple() && "simple type indices have no slots");
+  return Idx.getIndex() - TypeIndex::FirstNonSimpleIndex;
+}
+
 namespace {
 
 /// Implementation of CodeView type stream merging.
@@ -94,8 +99,22 @@ private:
 
   void addMapping(TypeIndex Idx);
 
-  bool remapTypeIndex(TypeIndex &Idx);
-  bool remapItemIndex(TypeIndex &Idx);
+  inline bool remapTypeIndex(TypeIndex &Idx) {
+    // If we're mapping a pure index stream, then IndexMap only contains
+    // mappings from OldIdStream -> NewIdStream, in which case we will need to
+    // use the special mapping from OldTypeStream -> NewTypeStream which was
+    // computed externally.  Regardless, we use this special map if and only if
+    // we are doing an id-only mapping.
+    if (!hasTypeStream())
+      return remapIndex(Idx, TypeLookup);
+
+    assert(TypeLookup.empty());
+    return remapIndex(Idx, IndexMap);
+  }
+  inline bool remapItemIndex(TypeIndex &Idx) {
+    assert(hasIdStream());
+    return remapIndex(Idx, IndexMap);
+  }
 
   bool hasTypeStream() const {
     return (UseGlobalHashes) ? (!!DestGlobalTypeStream) : (!!DestTypeStream);
@@ -105,17 +124,34 @@ private:
     return (UseGlobalHashes) ? (!!DestGlobalIdStream) : (!!DestIdStream);
   }
 
-  ArrayRef<uint8_t> serializeRemapped(const RemappedType &Record);
+  ArrayRef<uint8_t> remapIndices(const CVType &OriginalType,
+                                 MutableArrayRef<uint8_t> Storage);
 
-  bool remapIndices(RemappedType &Record, ArrayRef<TiReference> Refs);
+  inline bool remapIndex(TypeIndex &Idx, ArrayRef<TypeIndex> Map) {
+    if (LLVM_LIKELY(remapIndexSimple(Idx, Map)))
+      return true;
+
+    return remapIndexFallback(Idx, Map);
+  }
+
+  inline bool remapIndexSimple(TypeIndex &Idx, ArrayRef<TypeIndex> Map) const {
+    // Simple types are unchanged.
+    if (Idx.isSimple())
+      return true;
+
+    // Check if this type index refers to a record we've already translated
+    // successfully. If it refers to a type later in the stream or a record we
+    // had to defer, defer it until later pass.
+    unsigned MapPos = slotForIndex(Idx);
+    if (LLVM_UNLIKELY(MapPos >= Map.size() || Map[MapPos] == Untranslated))
+      return false;
 
-  bool remapIndex(TypeIndex &Idx, ArrayRef<TypeIndex> Map);
-
-  size_t slotForIndex(TypeIndex Idx) const {
-    assert(!Idx.isSimple() && "simple type indices have no slots");
-    return Idx.getIndex() - TypeIndex::FirstNonSimpleIndex;
+    Idx = Map[MapPos];
+    return true;
   }
 
+  bool remapIndexFallback(TypeIndex &Idx, ArrayRef<TypeIndex> Map);
+
   Error errorCorruptRecord() const {
     return llvm::make_error<CodeViewError>(cv_error_code::corrupt_record);
   }
@@ -153,27 +189,6 @@ private:
 
 } // end anonymous namespace
 
-ArrayRef<uint8_t>
-TypeStreamMerger::serializeRemapped(const RemappedType &Record) {
-  TypeIndex TI;
-  ArrayRef<uint8_t> OriginalData = Record.OriginalRecord.RecordData;
-  if (Record.Mappings.empty())
-    return OriginalData;
-
-  // At least one type index was remapped.  We copy the full record bytes,
-  // re-write each type index, then return that.
-  RemapStorage.resize(OriginalData.size());
-  ::memcpy(&RemapStorage[0], OriginalData.data(), OriginalData.size());
-  uint8_t *ContentBegin = RemapStorage.data() + sizeof(RecordPrefix);
-  for (const auto &M : Record.Mappings) {
-    // First 4 bytes of every record are the record prefix, but the mapping
-    // offset is relative to the content which starts after.
-    *(TypeIndex *)(ContentBegin + M.first) = M.second;
-  }
-  auto RemapRef = makeArrayRef(RemapStorage);
-  return RemapRef;
-}
-
 const TypeIndex TypeStreamMerger::Untranslated(SimpleTypeKind::NotTranslated);
 
 static bool isIdRecord(TypeLeafKind K) {
@@ -202,19 +217,9 @@ void TypeStreamMerger::addMapping(TypeIn
   }
 }
 
-bool TypeStreamMerger::remapIndex(TypeIndex &Idx, ArrayRef<TypeIndex> Map) {
-  // Simple types are unchanged.
-  if (Idx.isSimple())
-    return true;
-
-  // Check if this type index refers to a record we've already translated
-  // successfully. If it refers to a type later in the stream or a record we
-  // had to defer, defer it until later pass.
-  unsigned MapPos = slotForIndex(Idx);
-  if (MapPos < Map.size() && Map[MapPos] != Untranslated) {
-    Idx = Map[MapPos];
-    return true;
-  }
+bool TypeStreamMerger::remapIndexFallback(TypeIndex &Idx,
+                                          ArrayRef<TypeIndex> Map) {
+  size_t MapPos = slotForIndex(Idx);
 
   // If this is the second pass and this index isn't in the map, then it points
   // outside the current type stream, and this is a corrupt record.
@@ -232,24 +237,6 @@ bool TypeStreamMerger::remapIndex(TypeIn
   return false;
 }
 
-bool TypeStreamMerger::remapTypeIndex(TypeIndex &Idx) {
-  // If we're mapping a pure index stream, then IndexMap only contains mappings
-  // from OldIdStream -> NewIdStream, in which case we will need to use the
-  // special mapping from OldTypeStream -> NewTypeStream which was computed
-  // externally.  Regardless, we use this special map if and only if we are
-  // doing an id-only mapping.
-  if (!hasTypeStream())
-    return remapIndex(Idx, TypeLookup);
-
-  assert(TypeLookup.empty());
-  return remapIndex(Idx, IndexMap);
-}
-
-bool TypeStreamMerger::remapItemIndex(TypeIndex &Idx) {
-  assert(hasIdStream());
-  return remapIndex(Idx, IndexMap);
-}
-
 // Local hashing entry points
 Error TypeStreamMerger::mergeTypeRecords(MergingTypeTableBuilder &Dest,
                                          const CVTypeArray &Types) {
@@ -355,28 +342,25 @@ Error TypeStreamMerger::remapAllTypes(co
 }
 
 Error TypeStreamMerger::remapType(const CVType &Type) {
-  auto DoSerialize = [this, Type]() -> ArrayRef<uint8_t> {
-    RemappedType R(Type);
-    SmallVector<TiReference, 32> Refs;
-    discoverTypeIndices(Type.RecordData, Refs);
-    if (!remapIndices(R, Refs))
-      return {};
-    return serializeRemapped(R);
+  auto DoSerialize =
+      [this, Type](MutableArrayRef<uint8_t> Storage) -> ArrayRef<uint8_t> {
+    return remapIndices(Type, Storage);
   };
 
   TypeIndex DestIdx = Untranslated;
-  if (UseGlobalHashes) {
+  if (LLVM_LIKELY(UseGlobalHashes)) {
     GlobalTypeTableBuilder &Dest =
         isIdRecord(Type.kind()) ? *DestGlobalIdStream : *DestGlobalTypeStream;
     GloballyHashedType H = GlobalHashes[CurIndex.toArrayIndex()];
-    DestIdx = Dest.insertRecordAs(H, DoSerialize);
+    DestIdx = Dest.insertRecordAs(H, Type.RecordData.size(), DoSerialize);
   } else {
     MergingTypeTableBuilder &Dest =
         isIdRecord(Type.kind()) ? *DestIdStream : *DestTypeStream;
 
-    auto Data = DoSerialize();
-    if (!Data.empty())
-      DestIdx = Dest.insertRecordBytes(Data);
+    RemapStorage.resize(Type.RecordData.size());
+    ArrayRef<uint8_t> Result = DoSerialize(RemapStorage);
+    if (!Result.empty())
+      DestIdx = Dest.insertRecordBytes(Result);
   }
   addMapping(DestIdx);
 
@@ -386,27 +370,32 @@ Error TypeStreamMerger::remapType(const
   return Error::success();
 }
 
-bool TypeStreamMerger::remapIndices(RemappedType &Record,
-                                    ArrayRef<TiReference> Refs) {
-  ArrayRef<uint8_t> OriginalData = Record.OriginalRecord.content();
-  bool Success = true;
+ArrayRef<uint8_t>
+TypeStreamMerger::remapIndices(const CVType &OriginalType,
+                               MutableArrayRef<uint8_t> Storage) {
+  SmallVector<TiReference, 4> Refs;
+  discoverTypeIndices(OriginalType.RecordData, Refs);
+  if (Refs.empty())
+    return OriginalType.RecordData;
+
+  ::memcpy(Storage.data(), OriginalType.RecordData.data(),
+           OriginalType.RecordData.size());
+
+  uint8_t *DestContent = Storage.data() + sizeof(RecordPrefix);
+
   for (auto &Ref : Refs) {
-    uint32_t Offset = Ref.Offset;
-    ArrayRef<uint8_t> Bytes = OriginalData.slice(Ref.Offset, sizeof(TypeIndex));
-    ArrayRef<TypeIndex> TIs(reinterpret_cast<const TypeIndex *>(Bytes.data()),
-                            Ref.Count);
-    for (auto TI : TIs) {
-      TypeIndex NewTI = TI;
-      bool ThisSuccess = (Ref.Kind == TiRefKind::IndexRef)
-                             ? remapItemIndex(NewTI)
-                             : remapTypeIndex(NewTI);
-      if (ThisSuccess && NewTI != TI)
-        Record.Mappings.emplace_back(Offset, NewTI);
-      Offset += sizeof(TypeIndex);
-      Success &= ThisSuccess;
+    TypeIndex *DestTIs =
+        reinterpret_cast<TypeIndex *>(DestContent + Ref.Offset);
+
+    for (size_t I = 0; I < Ref.Count; ++I) {
+      TypeIndex &TI = DestTIs[I];
+      bool Success = (Ref.Kind == TiRefKind::IndexRef) ? remapItemIndex(TI)
+                                                       : remapTypeIndex(TI);
+      if (LLVM_UNLIKELY(!Success))
+        return {};
     }
   }
-  return Success;
+  return Storage;
 }
 
 Error llvm::codeview::mergeTypeRecords(MergingTypeTableBuilder &Dest,




More information about the llvm-commits mailing list