[dsymutil] Apply recursion workaround for threading

The DwarfLinker can have some very deep recursion that can max out the
(significantly smaller) stack when using threads. We don't want this
limitation when we only have a single thread. We already have this
workaround for the architecture-related threading. This patch applies
the same workaround to the parallel analysis and cloning.

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

llvm-svn: 329093
This commit is contained in:
Jonas Devlieghere 2018-04-03 18:01:18 +00:00
parent cc013f62c1
commit 4fad76ccde
3 changed files with 26 additions and 13 deletions

View File

@ -4301,8 +4301,6 @@ bool DwarfLinker::link(const DebugMap &Map) {
if (MaxDwarfVersion == 0) if (MaxDwarfVersion == 0)
MaxDwarfVersion = 3; MaxDwarfVersion = 3;
ThreadPool pool(2);
// These variables manage the list of processed object files. // These variables manage the list of processed object files.
// The mutex and condition variable are to ensure that this is thread safe. // The mutex and condition variable are to ensure that this is thread safe.
std::mutex ProcessedFilesMutex; std::mutex ProcessedFilesMutex;
@ -4310,7 +4308,7 @@ bool DwarfLinker::link(const DebugMap &Map) {
BitVector ProcessedFiles(NumObjects, false); BitVector ProcessedFiles(NumObjects, false);
// Now do analyzeContextInfo in parallel as it is particularly expensive. // Now do analyzeContextInfo in parallel as it is particularly expensive.
pool.async([&]() { auto AnalyzeLambda = [&]() {
for (unsigned i = 0, e = NumObjects; i != e; ++i) { for (unsigned i = 0, e = NumObjects; i != e; ++i) {
auto &LinkContext = ObjectContexts[i]; auto &LinkContext = ObjectContexts[i];
@ -4331,13 +4329,13 @@ bool DwarfLinker::link(const DebugMap &Map) {
ProcessedFiles.set(i); ProcessedFiles.set(i);
ProcessedFilesConditionVariable.notify_one(); ProcessedFilesConditionVariable.notify_one();
} }
}); };
// And then the remaining work in serial again. // And then the remaining work in serial again.
// Note, although this loop runs in serial, it can run in parallel with // Note, although this loop runs in serial, it can run in parallel with
// the analyzeContextInfo loop so long as we process files with indices >= // the analyzeContextInfo loop so long as we process files with indices >=
// than those processed by analyzeContextInfo. // than those processed by analyzeContextInfo.
pool.async([&]() { auto CloneLambda = [&]() {
for (unsigned i = 0, e = NumObjects; i != e; ++i) { for (unsigned i = 0, e = NumObjects; i != e; ++i) {
{ {
std::unique_lock<std::mutex> LockGuard(ProcessedFilesMutex); std::unique_lock<std::mutex> LockGuard(ProcessedFilesMutex);
@ -4397,9 +4395,20 @@ bool DwarfLinker::link(const DebugMap &Map) {
Streamer->emitAppleTypes(AppleTypes); Streamer->emitAppleTypes(AppleTypes);
Streamer->emitAppleObjc(AppleObjc); Streamer->emitAppleObjc(AppleObjc);
} }
}); };
// FIXME: The DwarfLinker can have some very deep recursion that can max
// out the (significantly smaller) stack when using threads. We don't
// want this limitation when we only have a single thread.
if (Options.Threads == 1) {
AnalyzeLambda();
CloneLambda();
} else {
ThreadPool pool(2);
pool.async(AnalyzeLambda);
pool.async(CloneLambda);
pool.wait(); pool.wait();
}
return Options.NoOutput ? true : Streamer->finish(Map); return Options.NoOutput ? true : Streamer->finish(Map);
} }

View File

@ -324,6 +324,11 @@ static Expected<LinkOptions> getOptions() {
inconvertibleErrorCode()); inconvertibleErrorCode());
} }
if (NumThreads == 0)
Options.Threads = llvm::thread::hardware_concurrency();
if (DumpDebugMap || Verbose)
Options.Threads = 1;
return Options; return Options;
} }
@ -480,12 +485,8 @@ int main(int argc, char **argv) {
return 1; return 1;
} }
if (NumThreads == 0) NumThreads =
NumThreads = llvm::thread::hardware_concurrency(); std::min<unsigned>(OptionsOrErr->Threads, DebugMapPtrsOrErr->size());
if (DumpDebugMap || Verbose)
NumThreads = 1;
NumThreads = std::min<unsigned>(NumThreads, DebugMapPtrsOrErr->size());
llvm::ThreadPool Threads(NumThreads); llvm::ThreadPool Threads(NumThreads);
// If there is more than one link to execute, we need to generate // If there is more than one link to execute, we need to generate

View File

@ -48,6 +48,9 @@ struct LinkOptions {
/// Do not check swiftmodule timestamp /// Do not check swiftmodule timestamp
bool NoTimestamp = false; bool NoTimestamp = false;
/// Number of threads.
unsigned Threads = 1;
/// -oso-prepend-path /// -oso-prepend-path
std::string PrependPath; std::string PrependPath;