From 5adb69ef86de078f2b6446a16501941dfbdf4f57 Mon Sep 17 00:00:00 2001 From: Chuanqi Xu Date: Fri, 14 Jun 2024 13:05:05 +0800 Subject: [PATCH] [Serialization] Don't read all declaration id eagerly when merge the tables See the post commit message in https://github.com/llvm/llvm-project/pull/92083 for rationale. Previously, when we merge the lookup tables, we will read the tables completely to get the data. But the above page shows that it might be problematic in specific cases where there a lot of DeclIDs to be read. In this patch, we mitigated the problem by not reading the contents of the merged tables. But we may need to pay for the additional memory usages. --- .../lib/Serialization/MultiOnDiskHashTable.h | 64 ++++++++++++++++--- 1 file changed, 54 insertions(+), 10 deletions(-) diff --git a/clang/lib/Serialization/MultiOnDiskHashTable.h b/clang/lib/Serialization/MultiOnDiskHashTable.h index a0d75ec3a9e76..f98394e904549 100644 --- a/clang/lib/Serialization/MultiOnDiskHashTable.h +++ b/clang/lib/Serialization/MultiOnDiskHashTable.h @@ -73,6 +73,51 @@ template class MultiOnDiskHashTable { struct MergedTable { std::vector Files; llvm::DenseMap Data; + + struct UnreadDataInfo { + Info *InfoObj; + const unsigned char *start; + unsigned DataLen; + }; + + llvm::DenseMap> + UnReadData; + + std::vector MergedOnDiskTables; + + void clear() { + for (OnDiskTable *ODT : MergedOnDiskTables) + delete ODT; + + MergedOnDiskTables.clear(); + } + + void readAll() { + for (const auto &Iter : UnReadData) { + internal_key_type Key = Iter.first; + data_type_builder ValueBuilder(Data[Key]); + + for (const UnreadDataInfo &I : Iter.second) + I.InfoObj->ReadDataInto(Key, I.start, I.DataLen, ValueBuilder); + } + + UnReadData.clear(); + clear(); + } + + data_type find(internal_key_type Key) { + auto UnreadIter = UnReadData.find(Key); + if (UnreadIter != UnReadData.end()) { + data_type_builder ValueBuilder(Data[Key]); + for (auto &I : UnreadIter->second) + I.InfoObj->ReadDataInto(Key, I.start, I.DataLen, ValueBuilder); + UnReadData.erase(UnreadIter); + } + + return Data[Key]; + } + + ~MergedTable() { clear(); } }; using Table = llvm::PointerUnion; @@ -159,13 +204,14 @@ template class MultiOnDiskHashTable { // FIXME: Don't rely on the OnDiskHashTable format here. auto L = InfoObj.ReadKeyDataLength(LocalPtr); const internal_key_type &Key = InfoObj.ReadKey(LocalPtr, L.first); - data_type_builder ValueBuilder(Merged->Data[Key]); - InfoObj.ReadDataInto(Key, LocalPtr + L.first, L.second, - ValueBuilder); + // Make sure Merged->Data contains every key. + (void)Merged->Data[Key]; + Merged->UnReadData[Key].push_back( + {&InfoObj, LocalPtr + L.first, L.second}); } Merged->Files.push_back(ODT->File); - delete ODT; + Merged->MergedOnDiskTables.push_back(ODT); } Tables.clear(); @@ -239,11 +285,8 @@ template class MultiOnDiskHashTable { internal_key_type Key = Info::GetInternalKey(EKey); auto KeyHash = Info::ComputeHash(Key); - if (MergedTable *M = getMergedTable()) { - auto It = M->Data.find(Key); - if (It != M->Data.end()) - Result = It->second; - } + if (MergedTable *M = getMergedTable()) + Result = M->find(Key); data_type_builder ResultBuilder(Result); @@ -268,6 +311,7 @@ template class MultiOnDiskHashTable { removeOverriddenTables(); if (MergedTable *M = getMergedTable()) { + M->readAll(); for (auto &KV : M->Data) Info::MergeDataInto(KV.second, ResultBuilder); } @@ -327,7 +371,7 @@ class MultiOnDiskHashTableGenerator { // Add all merged entries from Base to the generator. for (auto &KV : Merged->Data) { if (!Gen.contains(KV.first, Info)) - Gen.insert(KV.first, Info.ImportData(KV.second), Info); + Gen.insert(KV.first, Info.ImportData(Merged->find(KV.first)), Info); } } else { Writer.write(0);