llvm.org GIT mirror llvm / 773ac0d
[PDB] Fix quadratic behavior when writing a BinaryItemStream Binary streams are an abstraction over a discontiguous buffer. To write a discontiguous buffer, we want to copy each contiguous chunk individually. Currently BinaryStreams do not expose a way to iterate over the chunks, so the code repeatedly calls readLongestContiguousChunk() with an increasing offset. In order to lookup the chunk by offset, we would iterate the items list to figure out which chunk the offset is within. This is obviously O(n^2). Instead, pre-compute a table of offsets and do a binary search to figure out which chunk to use. This is still only an O(n^2) to O(n log n) improvement, but it's a very local fix that seems worth doing. This improves self-linking lld.exe with PDBs from 90s to 10s. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@307970 91177308-0d34-0410-b5e6-96231b3b80d8 Reid Kleckner 3 years ago
1 changed file(s) with 28 addition(s) and 15 deletion(s). Raw diff Collapse all Expand all
6161 return Error::success();
6262 }
6363
64 void setItems(ArrayRef ItemArray) { Items = ItemArray; }
64 void setItems(ArrayRef ItemArray) {
65 Items = ItemArray;
66 computeItemOffsets();
67 }
6568
6669 uint32_t getLength() override {
67 uint32_t Size = 0;
68 for (const auto &Item : Items)
69 Size += Traits::length(Item);
70 return Size;
70 return ItemEndOffsets.empty() ? 0 : ItemEndOffsets.back();
7171 }
7272
7373 private:
74 void computeItemOffsets() {
75 ItemEndOffsets.clear();
76 ItemEndOffsets.reserve(Items.size());
77 uint32_t CurrentOffset = 0;
78 for (const auto &Item : Items) {
79 uint32_t Len = Traits::length(Item);
80 assert(Len > 0 && "no empty items");
81 CurrentOffset += Len;
82 ItemEndOffsets.push_back(CurrentOffset);
83 }
84 }
85
7486 Expected translateOffsetIndex(uint32_t Offset) const {
75 uint32_t CurrentOffset = 0;
76 uint32_t CurrentIndex = 0;
77 for (const auto &Item : Items) {
78 if (CurrentOffset >= Offset)
79 break;
80 CurrentOffset += Traits::length(Item);
81 ++CurrentIndex;
82 }
83 if (CurrentOffset != Offset)
87 // Make sure the offset is somewhere in our items array.
88 if (Offset >= getLength())
8489 return make_error(stream_error_code::stream_too_short);
85 return CurrentIndex;
90 auto Iter = std::lower_bound(
91 ItemEndOffsets.begin(), ItemEndOffsets.end(), Offset,
92 [](const uint32_t &A, const uint32_t &B) { return A <= B; });
93 size_t Idx = std::distance(ItemEndOffsets.begin(), Iter);
94 assert(Idx < Items.size() && "binary search for offset failed");
95 return Idx;
8696 }
8797
8898 llvm::support::endianness Endian;
8999 ArrayRef Items;
100
101 // Sorted vector of offsets to accelerate lookup.
102 std::vector ItemEndOffsets;
90103 };
91104
92105 } // end namespace llvm