[ELF] - Speedup -r and --emit-relocs

This is "Bug 34688 - lld much slower than bfd when linking the linux kernel"

Inside copyRelocations() we have O(N*M) algorithm, where N - amount of
relocations and M - amount of symbols in symbol table. It isincredibly slow
for linking linux kernel.

Patch creates local search tables to speedup.
With this fix link time goes for me from 12.95s to 0.55s what is almost 23x
faster. (used release LLD).

Differential revision: https://reviews.llvm.org/D38129

llvm-svn: 314282
This commit is contained in:
George Rimar 2017-09-27 09:08:53 +00:00
parent 25ea19ea86
commit 5d6efd100b
3 changed files with 21 additions and 16 deletions

View File

@ -384,11 +384,6 @@ InputSectionBase *InputSection::getRelocatedSection() {
template <class ELFT, class RelTy>
void InputSection::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) {
InputSectionBase *RelocatedSection = getRelocatedSection();
// Loop is slow and have complexity O(N*M), where N - amount of
// relocations and M - amount of symbols in symbol table.
// That happens because getSymbolIndex(...) call below performs
// simple linear search.
for (const RelTy &Rel : Rels) {
uint32_t Type = Rel.getType(Config->IsMips64EL);
SymbolBody &Body = this->getFile<ELFT>()->getRelocTargetSym(Rel);

View File

@ -1355,18 +1355,24 @@ void SymbolTableBaseSection::addSymbol(SymbolBody *B) {
}
size_t SymbolTableBaseSection::getSymbolIndex(SymbolBody *Body) {
auto I = llvm::find_if(Symbols, [&](const SymbolTableEntry &E) {
if (E.Symbol == Body)
return true;
// This is used for -r, so we have to handle multiple section
// symbols being combined.
if (Body->Type == STT_SECTION && E.Symbol->Type == STT_SECTION)
return Body->getOutputSection() == E.Symbol->getOutputSection();
return false;
// Initializes symbol lookup tables lazily. This is used only
// for -r or -emit-relocs.
llvm::call_once(OnceFlag, [&] {
SymbolIndexMap.reserve(Symbols.size());
size_t I = 0;
for (const SymbolTableEntry &E : Symbols) {
if (E.Symbol->Type == STT_SECTION)
SectionIndexMap[E.Symbol->getOutputSection()] = ++I;
else
SymbolIndexMap[E.Symbol] = ++I;
}
});
if (I == Symbols.end())
return 0;
return I - Symbols.begin() + 1;
// Section symbols are mapped based on their output sections
// to maintain their semantics.
if (Body->Type == STT_SECTION)
return SectionIndexMap.lookup(Body->getOutputSection());
return SymbolIndexMap.lookup(Body);
}
template <class ELFT>

View File

@ -418,6 +418,10 @@ protected:
std::vector<SymbolTableEntry> Symbols;
StringTableSection &StrTabSec;
llvm::once_flag OnceFlag;
llvm::DenseMap<SymbolBody *, size_t> SymbolIndexMap;
llvm::DenseMap<OutputSection *, size_t> SectionIndexMap;
};
template <class ELFT>