Skip to content

Commit 09602d3

Browse files
committed
[ELF] Parallelize initializeLocalSymbols
ObjFile::parse combines symbol initialization and resolution. Many tasks unrelated to symbol resolution can be postponed and parallelized. This patch extracts local symbol initialization and parallelizes it. Technically the new function initializeLocalSymbols can be merged into ObjFile::postParse, but functions like getSrcMsg may access the uninitialized (all nullptr) local part of InputFile::symbols. Linking chrome: 1.02x as fast with glibc malloc, 1.04x as fast with mimalloc Reviewed By: ikudrin Differential Revision: https://reviews.llvm.org/D119909
1 parent 4bbc329 commit 09602d3

File tree

4 files changed

+68
-37
lines changed

4 files changed

+68
-37
lines changed

lld/ELF/Driver.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2219,6 +2219,25 @@ static uint32_t getAndFeatures() {
22192219
return ret;
22202220
}
22212221

2222+
static void initializeLocalSymbols(ELFFileBase *file) {
2223+
switch (config->ekind) {
2224+
case ELF32LEKind:
2225+
cast<ObjFile<ELF32LE>>(file)->initializeLocalSymbols();
2226+
break;
2227+
case ELF32BEKind:
2228+
cast<ObjFile<ELF32BE>>(file)->initializeLocalSymbols();
2229+
break;
2230+
case ELF64LEKind:
2231+
cast<ObjFile<ELF64LE>>(file)->initializeLocalSymbols();
2232+
break;
2233+
case ELF64BEKind:
2234+
cast<ObjFile<ELF64BE>>(file)->initializeLocalSymbols();
2235+
break;
2236+
default:
2237+
llvm_unreachable("");
2238+
}
2239+
}
2240+
22222241
static void postParseObjectFile(ELFFileBase *file) {
22232242
switch (config->ekind) {
22242243
case ELF32LEKind:
@@ -2357,6 +2376,7 @@ void LinkerDriver::link(opt::InputArgList &args) {
23572376

23582377
// No more lazy bitcode can be extracted at this point. Do post parse work
23592378
// like checking duplicate symbols.
2379+
parallelForEach(objectFiles, initializeLocalSymbols);
23602380
parallelForEach(objectFiles, postParseObjectFile);
23612381
parallelForEach(bitcodeFiles, [](BitcodeFile *file) { file->postParse(); });
23622382

@@ -2428,6 +2448,7 @@ void LinkerDriver::link(opt::InputArgList &args) {
24282448
// compileBitcodeFiles may have produced lto.tmp object files. After this, no
24292449
// more file will be added.
24302450
auto newObjectFiles = makeArrayRef(objectFiles).slice(numObjsBeforeLTO);
2451+
parallelForEach(newObjectFiles, initializeLocalSymbols);
24312452
parallelForEach(newObjectFiles, postParseObjectFile);
24322453

24332454
// Handle --exclude-libs again because lto.tmp may reference additional

lld/ELF/InputFiles.cpp

Lines changed: 39 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1021,41 +1021,6 @@ void ObjFile<ELFT>::initializeSymbols(const object::ELFFile<ELFT> &obj) {
10211021

10221022
ArrayRef<Elf_Sym> eSyms = this->getELFSyms<ELFT>();
10231023
symbols.resize(eSyms.size());
1024-
SymbolUnion *locals =
1025-
firstGlobal == 0
1026-
? nullptr
1027-
: getSpecificAllocSingleton<SymbolUnion>().Allocate(firstGlobal);
1028-
1029-
for (size_t i = 0, end = firstGlobal; i != end; ++i) {
1030-
const Elf_Sym &eSym = eSyms[i];
1031-
uint32_t secIdx = eSym.st_shndx;
1032-
if (LLVM_UNLIKELY(secIdx == SHN_XINDEX))
1033-
secIdx = check(getExtendedSymbolTableIndex<ELFT>(eSym, i, shndxTable));
1034-
else if (secIdx >= SHN_LORESERVE)
1035-
secIdx = 0;
1036-
if (LLVM_UNLIKELY(secIdx >= sections.size()))
1037-
fatal(toString(this) + ": invalid section index: " + Twine(secIdx));
1038-
if (LLVM_UNLIKELY(eSym.getBinding() != STB_LOCAL))
1039-
error(toString(this) + ": non-local symbol (" + Twine(i) +
1040-
") found at index < .symtab's sh_info (" + Twine(end) + ")");
1041-
1042-
InputSectionBase *sec = sections[secIdx];
1043-
uint8_t type = eSym.getType();
1044-
if (type == STT_FILE)
1045-
sourceFile = CHECK(eSym.getName(stringTable), this);
1046-
if (LLVM_UNLIKELY(stringTable.size() <= eSym.st_name))
1047-
fatal(toString(this) + ": invalid symbol name offset");
1048-
StringRef name(stringTable.data() + eSym.st_name);
1049-
1050-
symbols[i] = reinterpret_cast<Symbol *>(locals + i);
1051-
if (eSym.st_shndx == SHN_UNDEF || sec == &InputSection::discarded)
1052-
new (symbols[i]) Undefined(this, name, STB_LOCAL, eSym.st_other, type,
1053-
/*discardedSecIdx=*/secIdx);
1054-
else
1055-
new (symbols[i]) Defined(this, name, STB_LOCAL, eSym.st_other, type,
1056-
eSym.st_value, eSym.st_size, sec);
1057-
symbols[i]->isUsedInRegularObj = true;
1058-
}
10591024

10601025
// Some entries have been filled by LazyObjFile.
10611026
for (size_t i = firstGlobal, end = eSyms.size(); i != end; ++i)
@@ -1149,6 +1114,45 @@ void ObjFile<ELFT>::initializeSymbols(const object::ELFFile<ELFT> &obj) {
11491114
}
11501115
}
11511116

1117+
template <class ELFT> void ObjFile<ELFT>::initializeLocalSymbols() {
1118+
if (!firstGlobal)
1119+
return;
1120+
localSymStorage = std::make_unique<SymbolUnion[]>(firstGlobal);
1121+
SymbolUnion *locals = localSymStorage.get();
1122+
1123+
ArrayRef<Elf_Sym> eSyms = this->getELFSyms<ELFT>();
1124+
for (size_t i = 0, end = firstGlobal; i != end; ++i) {
1125+
const Elf_Sym &eSym = eSyms[i];
1126+
uint32_t secIdx = eSym.st_shndx;
1127+
if (LLVM_UNLIKELY(secIdx == SHN_XINDEX))
1128+
secIdx = check(getExtendedSymbolTableIndex<ELFT>(eSym, i, shndxTable));
1129+
else if (secIdx >= SHN_LORESERVE)
1130+
secIdx = 0;
1131+
if (LLVM_UNLIKELY(secIdx >= sections.size()))
1132+
fatal(toString(this) + ": invalid section index: " + Twine(secIdx));
1133+
if (LLVM_UNLIKELY(eSym.getBinding() != STB_LOCAL))
1134+
error(toString(this) + ": non-local symbol (" + Twine(i) +
1135+
") found at index < .symtab's sh_info (" + Twine(end) + ")");
1136+
1137+
InputSectionBase *sec = sections[secIdx];
1138+
uint8_t type = eSym.getType();
1139+
if (type == STT_FILE)
1140+
sourceFile = CHECK(eSym.getName(stringTable), this);
1141+
if (LLVM_UNLIKELY(stringTable.size() <= eSym.st_name))
1142+
fatal(toString(this) + ": invalid symbol name offset");
1143+
StringRef name(stringTable.data() + eSym.st_name);
1144+
1145+
symbols[i] = reinterpret_cast<Symbol *>(locals + i);
1146+
if (eSym.st_shndx == SHN_UNDEF || sec == &InputSection::discarded)
1147+
new (symbols[i]) Undefined(this, name, STB_LOCAL, eSym.st_other, type,
1148+
/*discardedSecIdx=*/secIdx);
1149+
else
1150+
new (symbols[i]) Defined(this, name, STB_LOCAL, eSym.st_other, type,
1151+
eSym.st_value, eSym.st_size, sec);
1152+
symbols[i]->isUsedInRegularObj = true;
1153+
}
1154+
}
1155+
11521156
// Called after all ObjFile::parse is called for all ObjFiles. This checks
11531157
// duplicate symbols and may do symbol property merge in the future.
11541158
template <class ELFT> void ObjFile<ELFT>::postParse() {

lld/ELF/InputFiles.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#define LLD_ELF_INPUT_FILES_H
1111

1212
#include "Config.h"
13+
#include "Symbols.h"
1314
#include "lld/Common/ErrorHandler.h"
1415
#include "lld/Common/LLVM.h"
1516
#include "lld/Common/Reproduce.h"
@@ -273,6 +274,7 @@ template <class ELFT> class ObjFile : public ELFFileBase {
273274
// Get cached DWARF information.
274275
DWARFCache *getDwarf();
275276

277+
void initializeLocalSymbols();
276278
void postParse();
277279

278280
private:
@@ -302,6 +304,9 @@ template <class ELFT> class ObjFile : public ELFFileBase {
302304
// If the section does not exist (which is common), the array is empty.
303305
ArrayRef<Elf_Word> shndxTable;
304306

307+
// Storage for local symbols.
308+
std::unique_ptr<SymbolUnion[]> localSymStorage;
309+
305310
// Debugging information to retrieve source file and line for error
306311
// reporting. Linker may find reasonable number of errors in a
307312
// single object file, so we cache debugging information in order to

lld/ELF/InputSection.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -297,9 +297,10 @@ std::string InputSectionBase::getObjMsg(uint64_t off) {
297297
if (!file->archiveName.empty())
298298
archive = (" in archive " + file->archiveName).str();
299299

300-
// Find a symbol that encloses a given location.
300+
// Find a symbol that encloses a given location. getObjMsg may be called
301+
// before ObjFile::initializeLocalSymbols where local symbols are initialized.
301302
for (Symbol *b : file->getSymbols())
302-
if (auto *d = dyn_cast<Defined>(b))
303+
if (auto *d = dyn_cast_or_null<Defined>(b))
303304
if (d->section == this && d->value <= off && off < d->value + d->size)
304305
return filename + ":(" + toString(*d) + ")" + archive;
305306

0 commit comments

Comments
 (0)