Skip to content

Commit f4d05d7

Browse files
committed
COFF: Parallelize InputFile::parse().
InputFile::parse() can be called in parallel with other calls of the same function. By doing that, time to self-link improves from 741 ms to 654 ms or 12% faster. This is probably the last low hanging fruit in terms of parallelism. Input file parsing and symbol table insertion takes 450 ms in total. If we want to optimize further, we probably have to parallelize symbol table insertion using concurrent hashmap or something. That's doable, but that's not easy, especially if you want to keep the exact same semantics and linking order. I'm not going to do that at least soon. Anyway, compared to r248019 (the change before the first attempt for parallelism), we achieved 36% performance improvement from 1022 ms to 654 ms. MSVC linker takes 3.3 seconds to link the same program. MSVC's ICF feature is very slow for some reason, but even if we disable the feature, it still takes about 1.2 seconds. Our number is probably good enough. llvm-svn: 248078
1 parent 2f957ac commit f4d05d7

1 file changed

Lines changed: 22 additions & 16 deletions

File tree

‎lld/COFF/SymbolTable.cpp‎

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "Error.h"
1313
#include "SymbolTable.h"
1414
#include "Symbols.h"
15+
#include "lld/Core/Parallel.h"
1516
#include "llvm/ADT/STLExtras.h"
1617
#include "llvm/LTO/LTOCodeGenerator.h"
1718
#include "llvm/Support/Debug.h"
@@ -56,13 +57,15 @@ void SymbolTable::readArchives() {
5657
if (ArchiveQueue.empty())
5758
return;
5859

60+
std::for_each(ArchiveQueue.begin(), ArchiveQueue.end(),
61+
[](ArchiveFile *File) { File->parse(); });
62+
5963
// Add lazy symbols to the symbol table. Lazy symbols that conflict
6064
// with existing undefined symbols are accumulated in LazySyms.
6165
std::vector<Symbol *> LazySyms;
6266
for (ArchiveFile *File : ArchiveQueue) {
6367
if (Config->Verbose)
6468
llvm::outs() << "Reading " << File->getShortName() << "\n";
65-
File->parse();
6669
for (Lazy &Sym : File->getLazySymbols())
6770
addLazy(&Sym, &LazySyms);
6871
}
@@ -80,22 +83,25 @@ void SymbolTable::readObjects() {
8083

8184
// Add defined and undefined symbols to the symbol table.
8285
std::vector<StringRef> Directives;
83-
for (size_t I = 0; I < ObjectQueue.size(); ++I) {
84-
InputFile *File = ObjectQueue[I];
85-
if (Config->Verbose)
86-
llvm::outs() << "Reading " << File->getShortName() << "\n";
87-
File->parse();
88-
// Adding symbols may add more files to ObjectQueue
89-
// (but not to ArchiveQueue).
90-
for (SymbolBody *Sym : File->getSymbols())
91-
if (Sym->isExternal())
92-
addSymbol(Sym);
93-
StringRef S = File->getDirectives();
94-
if (!S.empty()) {
95-
Directives.push_back(S);
86+
for (size_t I = 0; I < ObjectQueue.size();) {
87+
std::for_each(ObjectQueue.begin() + I, ObjectQueue.end(),
88+
[](InputFile *File) { File->parse(); });
89+
for (size_t E = ObjectQueue.size(); I != E; ++I) {
90+
InputFile *File = ObjectQueue[I];
9691
if (Config->Verbose)
97-
llvm::outs() << "Directives: " << File->getShortName()
98-
<< ": " << S << "\n";
92+
llvm::outs() << "Reading " << File->getShortName() << "\n";
93+
// Adding symbols may add more files to ObjectQueue
94+
// (but not to ArchiveQueue).
95+
for (SymbolBody *Sym : File->getSymbols())
96+
if (Sym->isExternal())
97+
addSymbol(Sym);
98+
StringRef S = File->getDirectives();
99+
if (!S.empty()) {
100+
Directives.push_back(S);
101+
if (Config->Verbose)
102+
llvm::outs() << "Directives: " << File->getShortName()
103+
<< ": " << S << "\n";
104+
}
99105
}
100106
}
101107
ObjectQueue.clear();

0 commit comments

Comments
 (0)