From 5fd2c900e90445c6efb7b97f8c663e588bcab81b Mon Sep 17 00:00:00 2001 From: serge-sans-paille Date: Tue, 2 Jul 2019 09:25:52 +0000 Subject: [PATCH] Selectively disable threading from gold Related: rhbz#1636479 --- llvm/include/llvm/LTO/LTO.h | 3 + llvm/include/llvm/LTO/LTOBackend.h | 3 + llvm/include/llvm/Support/ThreadPool.h | 7 ++ llvm/lib/LTO/LTO.cpp | 134 ++++++++++++++++++++++++- llvm/lib/LTO/LTOBackend.cpp | 48 ++++++++- llvm/lib/Support/ThreadPool.cpp | 6 +- llvm/tools/gold/gold-plugin.cpp | 7 +- 7 files changed, 197 insertions(+), 11 deletions(-) diff --git a/llvm/include/llvm/LTO/LTO.h b/llvm/include/llvm/LTO/LTO.h index 534d9b6f3f2..9dfda126540 100644 --- a/llvm/include/llvm/LTO/LTO.h +++ b/llvm/include/llvm/LTO/LTO.h @@ -212,6 +212,7 @@ typedef std::function( /// This ThinBackend runs the individual backend jobs in-process. ThinBackend createInProcessThinBackend(unsigned ParallelismLevel); +ThinBackend createInProcessThinBackendNoThread(unsigned ParallelismLevel); /// This ThinBackend writes individual module indexes to files, instead of /// running the individual backend jobs. This backend is for distributed builds @@ -281,6 +282,7 @@ public: /// The client will receive at most one callback (via either AddStream or /// Cache) for each task identifier. Error run(AddStreamFn AddStream, NativeObjectCache Cache = nullptr); + Error runNoThread(AddStreamFn AddStream, NativeObjectCache Cache = nullptr); private: Config Conf; @@ -397,6 +399,7 @@ private: const SymbolResolution *&ResI, const SymbolResolution *ResE); Error runRegularLTO(AddStreamFn AddStream); + Error runRegularLTONoThread(AddStreamFn AddStream); Error runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache); mutable bool CalledGetMaxTasks = false; diff --git a/llvm/include/llvm/LTO/LTOBackend.h b/llvm/include/llvm/LTO/LTOBackend.h index d4743f6940f..2d6461fa82e 100644 --- a/llvm/include/llvm/LTO/LTOBackend.h +++ b/llvm/include/llvm/LTO/LTOBackend.h @@ -39,6 +39,9 @@ namespace lto { Error backend(Config &C, AddStreamFn AddStream, unsigned ParallelCodeGenParallelismLevel, std::unique_ptr M, ModuleSummaryIndex &CombinedIndex); +Error backendNoThread(Config &C, AddStreamFn AddStream, + unsigned ParallelCodeGenParallelismLevel, + std::unique_ptr M, ModuleSummaryIndex &CombinedIndex); /// Runs a ThinLTO backend. Error thinBackend(Config &C, unsigned Task, AddStreamFn AddStream, Module &M, diff --git a/llvm/include/llvm/Support/ThreadPool.h b/llvm/include/llvm/Support/ThreadPool.h index 4fdbd528b21..60ea5097114 100644 --- a/llvm/include/llvm/Support/ThreadPool.h +++ b/llvm/include/llvm/Support/ThreadPool.h @@ -98,4 +98,11 @@ private: }; } +#ifndef ThreadPool +#undef LLVM_SUPPORT_THREAD_POOL_H +#define ThreadPool SequentialThreadPool +#include "llvm/Support/ThreadPool.h" +#undef ThreadPool +#endif + #endif // LLVM_SUPPORT_THREAD_POOL_H diff --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp index 3a955060dea..a7b4f45b18c 100644 --- a/llvm/lib/LTO/LTO.cpp +++ b/llvm/lib/LTO/LTO.cpp @@ -861,6 +861,58 @@ Error LTO::run(AddStreamFn AddStream, NativeObjectCache Cache) { return Result; } +Error LTO::runNoThread(AddStreamFn AddStream, NativeObjectCache Cache) { + // Compute "dead" symbols, we don't want to import/export these! + DenseSet GUIDPreservedSymbols; + DenseMap GUIDPrevailingResolutions; + for (auto &Res : GlobalResolutions) { + // Normally resolution have IR name of symbol. We can do nothing here + // otherwise. See comments in GlobalResolution struct for more details. + if (Res.second.IRName.empty()) + continue; + + GlobalValue::GUID GUID = GlobalValue::getGUID( + GlobalValue::dropLLVMManglingEscape(Res.second.IRName)); + + if (Res.second.VisibleOutsideSummary && Res.second.Prevailing) + GUIDPreservedSymbols.insert(GlobalValue::getGUID( + GlobalValue::dropLLVMManglingEscape(Res.second.IRName))); + + GUIDPrevailingResolutions[GUID] = + Res.second.Prevailing ? PrevailingType::Yes : PrevailingType::No; + } + + auto isPrevailing = [&](GlobalValue::GUID G) { + auto It = GUIDPrevailingResolutions.find(G); + if (It == GUIDPrevailingResolutions.end()) + return PrevailingType::Unknown; + return It->second; + }; + computeDeadSymbolsWithConstProp(ThinLTO.CombinedIndex, GUIDPreservedSymbols, + isPrevailing, Conf.OptLevel > 0); + + // Setup output file to emit statistics. + std::unique_ptr StatsFile = nullptr; + if (!Conf.StatsFile.empty()) { + EnableStatistics(false); + std::error_code EC; + StatsFile = + llvm::make_unique(Conf.StatsFile, EC, sys::fs::F_None); + if (EC) + return errorCodeToError(EC); + StatsFile->keep(); + } + + Error Result = runRegularLTONoThread(AddStream); + if (!Result) + Result = runThinLTO(AddStream, Cache); + + if (StatsFile) + PrintStatisticsJSON(StatsFile->os()); + + return Result; +} + Error LTO::runRegularLTO(AddStreamFn AddStream) { for (auto &M : RegularLTO.ModsWithSummaries) if (Error Err = linkRegularLTO(std::move(M), @@ -928,6 +980,73 @@ Error LTO::runRegularLTO(AddStreamFn AddStream) { std::move(RegularLTO.CombinedModule), ThinLTO.CombinedIndex); } +Error LTO::runRegularLTONoThread(AddStreamFn AddStream) { + for (auto &M : RegularLTO.ModsWithSummaries) + if (Error Err = linkRegularLTO(std::move(M), + /*LivenessFromIndex=*/true)) + return Err; + + // Make sure commons have the right size/alignment: we kept the largest from + // all the prevailing when adding the inputs, and we apply it here. + const DataLayout &DL = RegularLTO.CombinedModule->getDataLayout(); + for (auto &I : RegularLTO.Commons) { + if (!I.second.Prevailing) + // Don't do anything if no instance of this common was prevailing. + continue; + GlobalVariable *OldGV = RegularLTO.CombinedModule->getNamedGlobal(I.first); + if (OldGV && DL.getTypeAllocSize(OldGV->getValueType()) == I.second.Size) { + // Don't create a new global if the type is already correct, just make + // sure the alignment is correct. + OldGV->setAlignment(I.second.Align); + continue; + } + ArrayType *Ty = + ArrayType::get(Type::getInt8Ty(RegularLTO.Ctx), I.second.Size); + auto *GV = new GlobalVariable(*RegularLTO.CombinedModule, Ty, false, + GlobalValue::CommonLinkage, + ConstantAggregateZero::get(Ty), ""); + GV->setAlignment(I.second.Align); + if (OldGV) { + OldGV->replaceAllUsesWith(ConstantExpr::getBitCast(GV, OldGV->getType())); + GV->takeName(OldGV); + OldGV->eraseFromParent(); + } else { + GV->setName(I.first); + } + } + + if (Conf.PreOptModuleHook && + !Conf.PreOptModuleHook(0, *RegularLTO.CombinedModule)) + return Error::success(); + + if (!Conf.CodeGenOnly) { + for (const auto &R : GlobalResolutions) { + if (!R.second.isPrevailingIRSymbol()) + continue; + if (R.second.Partition != 0 && + R.second.Partition != GlobalResolution::External) + continue; + + GlobalValue *GV = + RegularLTO.CombinedModule->getNamedValue(R.second.IRName); + // Ignore symbols defined in other partitions. + // Also skip declarations, which are not allowed to have internal linkage. + if (!GV || GV->hasLocalLinkage() || GV->isDeclaration()) + continue; + GV->setUnnamedAddr(R.second.UnnamedAddr ? GlobalValue::UnnamedAddr::Global + : GlobalValue::UnnamedAddr::None); + if (EnableLTOInternalization && R.second.Partition == 0) + GV->setLinkage(GlobalValue::InternalLinkage); + } + + if (Conf.PostInternalizeModuleHook && + !Conf.PostInternalizeModuleHook(0, *RegularLTO.CombinedModule)) + return Error::success(); + } + return backendNoThread(Conf, AddStream, RegularLTO.ParallelCodeGenParallelismLevel, + std::move(RegularLTO.CombinedModule), ThinLTO.CombinedIndex); +} + /// This class defines the interface to the ThinLTO backend. class lto::ThinBackendProc { protected: @@ -952,8 +1071,9 @@ public: }; namespace { +template class InProcessThinBackend : public ThinBackendProc { - ThreadPool BackendThreadPool; + ThreadEngine BackendThreadPool; AddStreamFn AddStream; NativeObjectCache Cache; std::set CfiFunctionDefs; @@ -1065,9 +1185,19 @@ ThinBackend lto::createInProcessThinBackend(unsigned ParallelismLevel) { return [=](Config &Conf, ModuleSummaryIndex &CombinedIndex, const StringMap &ModuleToDefinedGVSummaries, AddStreamFn AddStream, NativeObjectCache Cache) { - return llvm::make_unique( + return llvm::make_unique>( + Conf, CombinedIndex, ParallelismLevel, ModuleToDefinedGVSummaries, + AddStream, Cache); + }; +} +ThinBackend lto::createInProcessThinBackendNoThread(unsigned ParallelismLevel) { + return [=](Config &Conf, ModuleSummaryIndex &CombinedIndex, + const StringMap &ModuleToDefinedGVSummaries, + AddStreamFn AddStream, NativeObjectCache Cache) { + ThinBackendProc* Backend = new InProcessThinBackend( Conf, CombinedIndex, ParallelismLevel, ModuleToDefinedGVSummaries, AddStream, Cache); + return std::unique_ptr(Backend); }; } diff --git a/llvm/lib/LTO/LTOBackend.cpp b/llvm/lib/LTO/LTOBackend.cpp index 926c419e34a..2c263ed86a9 100644 --- a/llvm/lib/LTO/LTOBackend.cpp +++ b/llvm/lib/LTO/LTOBackend.cpp @@ -333,10 +333,11 @@ void codegen(Config &Conf, TargetMachine *TM, AddStreamFn AddStream, DwoOut->keep(); } -void splitCodeGen(Config &C, TargetMachine *TM, AddStreamFn AddStream, +template +static void splitCodeGen_(Config &C, TargetMachine *TM, AddStreamFn AddStream, unsigned ParallelCodeGenParallelismLevel, std::unique_ptr Mod) { - ThreadPool CodegenThreadPool(ParallelCodeGenParallelismLevel); + ThreadPoolEngine CodegenThreadPool(ParallelCodeGenParallelismLevel); unsigned ThreadCount = 0; const Target *T = &TM->getTarget(); @@ -380,6 +381,17 @@ void splitCodeGen(Config &C, TargetMachine *TM, AddStreamFn AddStream, // can leave the function scope. CodegenThreadPool.wait(); } +void splitCodeGen(Config &C, TargetMachine *TM, AddStreamFn AddStream, + unsigned ParallelCodeGenParallelismLevel, + std::unique_ptr Mod) { + splitCodeGen_(C, TM, AddStream, ParallelCodeGenParallelismLevel, std::move(Mod)); +} + +void splitCodeGenNoThread(Config &C, TargetMachine *TM, AddStreamFn AddStream, + unsigned ParallelCodeGenParallelismLevel, + std::unique_ptr Mod) { + splitCodeGen_(C, TM, AddStream, ParallelCodeGenParallelismLevel, std::move(Mod)); +} Expected initAndLookupTarget(Config &C, Module &Mod) { if (!C.OverrideTriple.empty()) @@ -439,6 +451,38 @@ Error lto::backend(Config &C, AddStreamFn AddStream, return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile)); } +Error lto::backendNoThread(Config &C, AddStreamFn AddStream, + unsigned ParallelCodeGenParallelismLevel, + std::unique_ptr Mod, + ModuleSummaryIndex &CombinedIndex) { + Expected TOrErr = initAndLookupTarget(C, *Mod); + if (!TOrErr) + return TOrErr.takeError(); + + std::unique_ptr TM = createTargetMachine(C, *TOrErr, *Mod); + + // Setup optimization remarks. + auto DiagFileOrErr = lto::setupOptimizationRemarks( + Mod->getContext(), C.RemarksFilename, C.RemarksWithHotness); + if (!DiagFileOrErr) + return DiagFileOrErr.takeError(); + auto DiagnosticOutputFile = std::move(*DiagFileOrErr); + + if (!C.CodeGenOnly) { + if (!opt(C, TM.get(), 0, *Mod, /*IsThinLTO=*/false, + /*ExportSummary=*/&CombinedIndex, /*ImportSummary=*/nullptr)) + return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile)); + } + + if (ParallelCodeGenParallelismLevel == 1) { + codegen(C, TM.get(), AddStream, 0, *Mod); + } else { + splitCodeGenNoThread(C, TM.get(), AddStream, ParallelCodeGenParallelismLevel, + std::move(Mod)); + } + return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile)); +} + static void dropDeadSymbols(Module &Mod, const GVSummaryMapTy &DefinedGlobals, const ModuleSummaryIndex &Index) { std::vector DeadGVs; diff --git a/llvm/lib/Support/ThreadPool.cpp b/llvm/lib/Support/ThreadPool.cpp index d0212ca1346..3d760edbcb7 100644 --- a/llvm/lib/Support/ThreadPool.cpp +++ b/llvm/lib/Support/ThreadPool.cpp @@ -19,8 +19,6 @@ using namespace llvm; -#if LLVM_ENABLE_THREADS - // Default to hardware_concurrency ThreadPool::ThreadPool() : ThreadPool(hardware_concurrency()) {} @@ -107,7 +105,7 @@ ThreadPool::~ThreadPool() { Worker.join(); } -#else // LLVM_ENABLE_THREADS Disabled +#define ThreadPool SequentialThreadPool ThreadPool::ThreadPool() : ThreadPool(0) {} @@ -142,5 +140,3 @@ std::shared_future ThreadPool::asyncImpl(TaskTy Task) { ThreadPool::~ThreadPool() { wait(); } - -#endif diff --git a/llvm/tools/gold/gold-plugin.cpp b/llvm/tools/gold/gold-plugin.cpp index 738cafa6cac..8ef75d2589c 100644 --- a/llvm/tools/gold/gold-plugin.cpp +++ b/llvm/tools/gold/gold-plugin.cpp @@ -848,7 +848,7 @@ static std::unique_ptr createLTO(IndexWriteCallback OnIndexWrite, Conf.DisableVerify = options::DisableVerify; Conf.OptLevel = options::OptLevel; if (options::Parallelism) - Backend = createInProcessThinBackend(options::Parallelism); + Backend = createInProcessThinBackendNoThread(options::Parallelism); if (options::thinlto_index_only) { std::string OldPrefix, NewPrefix; getThinLTOOldAndNewPrefix(OldPrefix, NewPrefix); @@ -856,6 +856,9 @@ static std::unique_ptr createLTO(IndexWriteCallback OnIndexWrite, options::thinlto_emit_imports_files, LinkedObjectsFile, OnIndexWrite); } + if(!Backend) + Backend = createInProcessThinBackendNoThread(llvm::heavyweight_hardware_concurrency()); + Conf.OverrideTriple = options::triple; Conf.DefaultTriple = sys::getDefaultTargetTriple(); @@ -1039,7 +1042,7 @@ static std::vector, bool>> runLTO() { if (!options::cache_dir.empty()) Cache = check(localCache(options::cache_dir, AddBuffer)); - check(Lto->run(AddStream, Cache)); + check(Lto->runNoThread(AddStream, Cache)); // Write empty output files that may be expected by the distributed build // system. -- 2.20.1