================ @@ -2142,3 +2190,326 @@ std::vector<int> lto::generateModulesOrdering(ArrayRef<BitcodeModule *> R) { }); return ModulesOrdering; } + +namespace { +// For this out-of-process backend no codegen is done when invoked for each +// task. Instead we generate the required information (e.g. the summary index +// shard,import list, etc..) to allow for the codegen to be performed +// externally . This backend's `wait` function then invokes an external +// distributor process to do backend compilations. +class OutOfProcessThinBackend : public CGThinBackend { + using SString = SmallString<128>; + + AddBufferFn AddBuffer; + + BumpPtrAllocator Alloc; + StringSaver Saver{Alloc}; + + SString LinkerOutputFile; + StringRef LinkerVersion; + SString RemoteOptTool; + SString DistributorPath; + bool SaveTemps; + + SmallVector<StringRef, 0> CodegenOptions; + DenseSet<StringRef> AdditionalInputs; + + // Information specific to individual backend compilation job. + struct Job { + unsigned Task; + StringRef ModuleID; + StringRef Triple; + StringRef NativeObjectPath; + StringRef SummaryIndexPath; + ImportsFilesContainer ImportFiles; + }; + // The set of backend compilations jobs. + SmallVector<Job> Jobs; + + // A unique string to identify the current link. + SmallString<8> UID; + +public: + OutOfProcessThinBackend( + const Config &Conf, ModuleSummaryIndex &CombinedIndex, + ThreadPoolStrategy ThinLTOParallelism, + const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries, + AddStreamFn AddStream, AddBufferFn AddBuffer, + lto::IndexWriteCallback OnWrite, bool ShouldEmitIndexFiles, + bool ShouldEmitImportsFiles, StringRef LinkerOutputFile, + StringRef LinkerVersion, StringRef RemoteOptTool, StringRef Distributor, + bool SaveTemps) + : CGThinBackend(Conf, CombinedIndex, ModuleToDefinedGVSummaries, OnWrite, + ShouldEmitIndexFiles, ShouldEmitImportsFiles, + ThinLTOParallelism), + AddBuffer(std::move(AddBuffer)), LinkerOutputFile(LinkerOutputFile), + LinkerVersion(LinkerVersion), RemoteOptTool(RemoteOptTool), + DistributorPath(Distributor), SaveTemps(SaveTemps) {} + + virtual void setup(unsigned MaxTasks) override { + UID = itostr(sys::Process::getProcessId()); + Jobs.resize((size_t)MaxTasks); + } + + Error start( + unsigned Task, BitcodeModule BM, + const FunctionImporter::ImportMapTy &ImportList, + const FunctionImporter::ExportSetTy &ExportList, + const std::map<GlobalValue::GUID, GlobalValue::LinkageTypes> &ResolvedODR, + MapVector<StringRef, BitcodeModule> &ModuleMap, + DenseMap<StringRef, std::string> &ModuleTriples) override { + + StringRef ModulePath = BM.getModuleIdentifier(); + + SString ObjFilePath = sys::path::parent_path(LinkerOutputFile); + sys::path::append(ObjFilePath, sys::path::stem(ModulePath) + "." + + itostr(Task) + "." + UID + ".native.o"); + + Job &J = Jobs[Task - 1]; /*Task 0 is reserved*/ + J = {Task, + ModulePath, + ModuleTriples[ModulePath], + Saver.save(ObjFilePath.str()), + Saver.save(ObjFilePath.str() + ".thinlto.bc"), + {}}; + + assert(ModuleToDefinedGVSummaries.count(ModulePath)); + BackendThreadPool.async( + [=](Job &J, const FunctionImporter::ImportMapTy &ImportList) { + if (LLVM_ENABLE_THREADS && Conf.TimeTraceEnabled) + timeTraceProfilerInitialize(Conf.TimeTraceGranularity, + "thin backend"); + if (auto E = emitFiles(ImportList, J.ModuleID, J.SummaryIndexPath, + J.ModuleID.str(), J.ImportFiles)) { + std::unique_lock<std::mutex> L(ErrMu); + if (Err) + Err = joinErrors(std::move(*Err), std::move(E)); + else + Err = std::move(E); + } + if (LLVM_ENABLE_THREADS && Conf.TimeTraceEnabled) + timeTraceProfilerFinishThread(); + }, + std::ref(J), std::ref(ImportList)); + + return Error::success(); + } + + // Derive a set of Clang options that will be shared/common for all DTLTO + // backend compilations. We are intentionally minimal here as these options + // must remain synchronized with the behavior of Clang. DTLTO does not support + // all the features available with in-process LTO. More features are expected + // to be added over time. Users can specify Clang options directly if a + // feature is not supported. Note that explicitly specified options that imply + // additional input or output file dependencies must be communicated to the + // distribution system, potentially by setting extra options on the + // distributor program. + // TODO: If this strategy of deriving options proves insufficient, alternative + // approaches should be considered, such as: + // - A serialization/deserialization format for LTO configuration. + // - Modifying LLD to be the tool that performs the backend compilations. + void buildCommonRemoteOptToolOptions() { + const lto::Config &C = Conf; + auto &Ops = CodegenOptions; + llvm::Triple TT{Jobs.front().Triple}; + + Ops.push_back(Saver.save("-O" + Twine(C.OptLevel))); + + if (C.Options.EmitAddrsig) + Ops.push_back("-faddrsig"); + if (C.Options.FunctionSections) + Ops.push_back("-ffunction-sections"); + if (C.Options.DataSections) + Ops.push_back("-fdata-sections"); + + if (C.RelocModel == Reloc::PIC_) + // Clang doesn't have -fpic for all triples. + if (!TT.isOSBinFormatCOFF()) + Ops.push_back("-fpic"); + + // Turn on/off warnings about profile cfg mismatch (default on) + // --lto-pgo-warn-mismatch. + if (!C.PGOWarnMismatch) { + Ops.push_back("-mllvm"); + Ops.push_back("-no-pgo-warn-mismatch"); + } + + // Enable sample-based profile guided optimizations. + // Sample profile file path --lto-sample-profile=<value>. + if (!C.SampleProfile.empty()) { + Ops.push_back( + Saver.save("-fprofile-sample-use=" + Twine(C.SampleProfile))); + AdditionalInputs.insert(C.SampleProfile); + } + + // Forward any supplied options. + if (!ThinLTORemoteOptToolArgs.empty()) + for (auto &a : ThinLTORemoteOptToolArgs) + Ops.push_back(a); + + // We don't know which of those options will be used by Clang. + Ops.push_back("-Wno-unused-command-line-argument"); + } + + // Generates a JSON file describing the backend compilations, for the + // distributor. + bool emitDistributorJson(StringRef DistributorJson) { + using json::Array; + std::error_code EC; + raw_fd_ostream OS(DistributorJson, EC); + if (EC) + return false; + + json::OStream JOS(OS); + JOS.object([&]() { + // Information common to all jobs note that we use a custom syntax for + // referencing by index into the job input and output file arrays. + JOS.attributeObject("common", [&]() { + JOS.attribute("linker_output", LinkerOutputFile); + JOS.attribute("linker_version", LinkerVersion); + + // Common command line template. + JOS.attributeArray("args", [&]() { + JOS.value(RemoteOptTool); ---------------- bd1976bris wrote:
After discussion on the linked comment thread I have adopted your suggestion of --thinlto-remote-compiler. https://github.com/llvm/llvm-project/pull/126654 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits