Skip to content

Commit ccd4e5e

Browse files
committedFeb 5, 2019
[COFF] Avoid O(n^2) accesses into PartialSections
For MinGW, unique partial sections are much more common, e.g. comdat functions get sections named e.g. text$symbol. A moderate sized example of this contains over 200K Chunks which create 174K unique PartialSections. Prior to SVN r352928 (D57574), linking this took around 1,5 seconds for me, while it afterwards takes around 13 minutes. After this patch, the linking time is back to what it was before. The std::find_if in findPartialSection will do a linear scan of the whole container until a match is found. To use something like binary_search or the std::set container's own methods, we'd need to already have a PartialSection*. Reinstate a proper map instead of having a set with a custom sorting comparator. Differential Revision: https://reviews.llvm.org/D57666 llvm-svn: 353146
1 parent 537a718 commit ccd4e5e

File tree

1 file changed

+21
-21
lines changed

1 file changed

+21
-21
lines changed
 

‎lld/COFF/Writer.cpp

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -159,15 +159,12 @@ class CVDebugRecordChunk : public Chunk {
159159
// PartialSection represents a group of chunks that contribute to an
160160
// OutputSection. Collating a collection of PartialSections of same name and
161161
// characteristics constitutes the OutputSection.
162-
class PartialSection {
162+
class PartialSectionKey {
163163
public:
164-
PartialSection(StringRef N, uint32_t Chars)
165-
: Name(N), Characteristics(Chars) {}
166164
StringRef Name;
167165
unsigned Characteristics;
168-
std::vector<Chunk *> Chunks;
169166

170-
bool operator<(const PartialSection &Other) const {
167+
bool operator<(const PartialSectionKey &Other) const {
171168
int C = Name.compare(Other.Name);
172169
if (C == 1)
173170
return false;
@@ -177,10 +174,13 @@ class PartialSection {
177174
}
178175
};
179176

180-
struct PartialLess {
181-
bool operator()(PartialSection *L, PartialSection *R) const {
182-
return *L < *R;
183-
}
177+
class PartialSection {
178+
public:
179+
PartialSection(StringRef N, uint32_t Chars)
180+
: Name(N), Characteristics(Chars) {}
181+
StringRef Name;
182+
unsigned Characteristics;
183+
std::vector<Chunk *> Chunks;
184184
};
185185

186186
// The writer writes a SymbolTable result to a file.
@@ -234,7 +234,7 @@ class Writer {
234234
uint32_t getSizeOfInitializedData();
235235

236236
std::unique_ptr<FileOutputBuffer> &Buffer;
237-
std::set<PartialSection *, PartialLess> PartialSections;
237+
std::map<PartialSectionKey, PartialSection *> PartialSections;
238238
std::vector<OutputSection *> OutputSections;
239239
std::vector<char> Strtab;
240240
std::vector<llvm::object::coff_symbol16> OutputSymtab;
@@ -628,7 +628,8 @@ bool Writer::fixGnuImportChunks() {
628628

629629
// Make sure all .idata$* section chunks are mapped as RDATA in order to
630630
// be sorted into the same sections as our own synthesized .idata chunks.
631-
for (PartialSection *PSec : PartialSections) {
631+
for (auto It : PartialSections) {
632+
PartialSection *PSec = It.second;
632633
if (!PSec->Name.startswith(".idata"))
633634
continue;
634635
if (PSec->Characteristics == RDATA)
@@ -642,7 +643,8 @@ bool Writer::fixGnuImportChunks() {
642643
bool HasIdata = false;
643644
// Sort all .idata$* chunks, grouping chunks from the same library,
644645
// with alphabetical ordering of the object fils within a library.
645-
for (PartialSection *PSec : PartialSections) {
646+
for (auto It : PartialSections) {
647+
PartialSection *PSec = It.second;
646648
if (!PSec->Name.startswith(".idata"))
647649
continue;
648650

@@ -773,8 +775,8 @@ void Writer::createSections() {
773775

774776
// Process an /order option.
775777
if (!Config->Order.empty())
776-
for (PartialSection *PSec : PartialSections)
777-
sortBySectionOrder(PSec->Chunks);
778+
for (auto It : PartialSections)
779+
sortBySectionOrder(It.second->Chunks);
778780

779781
if (HasIdata)
780782
locateImportTables();
@@ -783,7 +785,8 @@ void Writer::createSections() {
783785
// '$' and all following characters in input section names are
784786
// discarded when determining output section. So, .text$foo
785787
// contributes to .text, for example. See PE/COFF spec 3.2.
786-
for (PartialSection *PSec : PartialSections) {
788+
for (auto It : PartialSections) {
789+
PartialSection *PSec = It.second;
787790
StringRef Name = getOutputSectionName(PSec->Name);
788791
uint32_t OutChars = PSec->Characteristics;
789792

@@ -1771,19 +1774,16 @@ void Writer::addBaserelBlocks(std::vector<Baserel> &V) {
17711774

17721775
PartialSection *Writer::createPartialSection(StringRef Name,
17731776
uint32_t OutChars) {
1774-
PartialSection *PSec = findPartialSection(Name, OutChars);
1777+
PartialSection *&PSec = PartialSections[{Name, OutChars}];
17751778
if (PSec)
17761779
return PSec;
17771780
PSec = make<PartialSection>(Name, OutChars);
1778-
PartialSections.insert(PSec);
17791781
return PSec;
17801782
}
17811783

17821784
PartialSection *Writer::findPartialSection(StringRef Name, uint32_t OutChars) {
1783-
auto It = find_if(PartialSections, [&](PartialSection *P) {
1784-
return P->Name == Name && P->Characteristics == OutChars;
1785-
});
1785+
auto It = PartialSections.find({Name, OutChars});
17861786
if (It != PartialSections.end())
1787-
return *It;
1787+
return It->second;
17881788
return nullptr;
17891789
}

0 commit comments

Comments
 (0)
Please sign in to comment.