LLVM 24.0.0git
DTLTO.cpp
Go to the documentation of this file.
1//===- DTLTO.cpp - Integrated Distributed ThinLTO implementation ----------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8// \file
9// This file implements support functions for Integrated Distributed ThinLTO,
10// focusing on preparing complilation jobs for distribution.
11//
12//===----------------------------------------------------------------------===//
13
14#include "llvm/DTLTO/DTLTO.h"
15
16#include "llvm/ADT/STLExtras.h"
17#include "llvm/ADT/ScopeExit.h"
20#include "llvm/ADT/StringRef.h"
21#include "llvm/LTO/LTO.h"
24#include "llvm/Support/Path.h"
28
29#include <string>
30#include <system_error>
31#include <utility>
32#include <vector>
33
34using namespace llvm;
35
36// Experimentation showed that serial deletion is most efficient, hence
37// a single thread.
38lto::DTLTO::BackgroundDeletion::BackgroundDeletion()
40
41lto::DTLTO::BackgroundDeletion::~BackgroundDeletion() { waitForTasks(); }
42
43void lto::DTLTO::BackgroundDeletion::waitForTasks() {
44 wait();
45 for (const std::string &Warning : Warnings)
46 errs() << "warning: could not remove the file " << Warning << "\n";
47 Warnings.clear();
48}
49
50void lto::DTLTO::BackgroundDeletion::removeFiles(
51 std::vector<std::string> &&Files, const Config &Conf) {
52 if (Files.empty())
53 return;
54
55 async([this, Files = std::move(Files), TTE = Conf.TimeTraceEnabled,
56 TTG = Conf.TimeTraceGranularity] {
57 if (LLVM_ENABLE_THREADS && TTE)
58 timeTraceProfilerInitialize(TTG, "Remove DTLTO temporary files");
59 {
60 TimeTraceScope TimeScope("Remove DTLTO temporary files");
61 for (const std::string &Path : Files) {
62 std::error_code EC = sys::fs::remove(Path, true);
63 if (!EC ||
64 EC == std::make_error_code(std::errc::no_such_file_or_directory))
65 continue;
66
67 Warnings.emplace_back("'" + Path + "': " + EC.message());
68 }
69 }
70 if (LLVM_ENABLE_THREADS && TTE)
72 });
73}
74
75void lto::DTLTO::waitForCleanup() { BackgroundDeleter.waitForTasks(); }
76
77// Remove temporary files created to enable distribution.
79 if (SaveTemps)
80 return;
81
82 BackgroundDeleter.removeFiles(std::move(CleanupList), Conf);
83}
84
85// Runs the DTLTO thin link phase, producing per-module summary indices,
86// import lists, and cache keys for distribution.
87Error lto::DTLTO::performThinLink() {
88 size_t NumTasks = getMaxTasks();
89 SummaryIndexFiles.resize(NumTasks);
90 ImportsFilesList.resize(NumTasks);
91 CacheKeysList.resize(NumTasks);
92
93 lto::Config &Cfg = getConfig();
95 [&](size_t task) -> std::unique_ptr<raw_svector_ostream> {
96 return std::make_unique<raw_svector_ostream>(SummaryIndexFiles[task]);
97 };
98 Cfg.GetCacheKeyOutputString = [&](size_t task) -> std::string & {
99 return CacheKeysList[task];
100 };
102 [&](size_t task) -> std::vector<std::string> & {
103 return ImportsFilesList[task];
104 };
105 return Base::run(AddStreamFunc, {});
106}
107
108// Runs the DTLTO pipeline.
110 scope_exit CleanUp([this]() { cleanup(); });
111
112 AddStreamFunc = AddStream;
113 Cache = std::move(CacheParam);
114 Conf.Dtlto = 1;
116
117 if (Error Err = performThinLink())
118 return Err;
119
120 ThinLTOTaskOffset = RegularLTO.ParallelCodeGenParallelismLevel;
121 DistributorParams.TargetTriple = RegularLTO.CombinedModule->getTargetTriple();
122
123 if (Error Err = prepareDtltoJobs())
124 return Err;
125 if (Error Err = extractLTOInputs())
126 return Err;
127 if (Error Err = performCodegen())
128 return Err;
129 if (Error Err = addObjectFilesToLink())
130 return Err;
131 return Error::success();
132}
133
134// Probes the LTO cache for a compiled native object for the given job.
135Error lto::DTLTO::checkCacheHit(Job &J) {
136 if (!Cache.isValid())
137 return Error::success();
138
139 TimeTraceScope TimeScope("Check cache for DTLTO", J.SummaryIndexPath);
140
141 auto CacheAddStreamExp = Cache(J.Task, J.CacheKey, J.ModuleID);
142 if (Error Err = CacheAddStreamExp.takeError())
143 return Err;
144 AddStreamFn &CacheAddStream = *CacheAddStreamExp;
145 // If CacheAddStream is null, we have a cache hit and at this point
146 // object file is already passed back to the linker.
147 if (!CacheAddStream) {
148 J.Cached = true; // Cache hit, mark the job as cached.
149 CachedJobs.fetch_add(1);
150 } else {
151 // If CacheAddStream is not null, we have a cache miss and we need to
152 // run the backend for codegen. Save cache 'add stream'
153 // function for a later use.
154 J.CacheAddStream = std::move(CacheAddStream);
155 }
156 return Error::success();
157}
158
159// Prepares a single DTLTO backend compilation job for a ThinLTO module.
160Error lto::DTLTO::prepareDtltoJob(StringRef ModulePath, unsigned Task) {
161 assert(Task >= ThinLTOTaskOffset && Task - ThinLTOTaskOffset < Jobs.size() &&
162 "Task index out of range for Jobs");
163 assert(Task < SummaryIndexFiles.size() && "Task index out of range");
164
165 SString ObjFilePath =
166 sys::path::parent_path(DistributorParams.LinkerOutputFile);
167 sys::path::append(ObjFilePath, sys::path::stem(ModulePath) + "." +
168 itostr(Task) + "." + UID + ".native.o");
169
170 SString SummaryIndexPathStr = ObjFilePath;
171 SummaryIndexPathStr += ".thinlto.bc";
172 SString ImportsPathStr = ModulePath;
173 ImportsPathStr += ".imports";
174
175 Job &J = Jobs[Task - ThinLTOTaskOffset];
176 J = {Task,
177 ModulePath,
178 Saver.save(ObjFilePath.str()),
179 Saver.save(SummaryIndexPathStr.str()),
180 Saver.save(ImportsPathStr.str()),
181 ImportsFilesList[Task],
182 CacheKeysList[Task],
183 nullptr,
184 false};
185
186 if (Error Err = checkCacheHit(J))
187 return Err;
188 if (!J.Cached) {
189 InputModuleIDsToExtract.insert(J.ModuleID);
190 for (StringRef ImportPath : J.ImportsFilesList)
191 InputModuleIDsToExtract.insert(ImportPath);
192
193 TimeTraceScope JobScope("Emit individual index for DTLTO",
194 J.SummaryIndexPath);
195 if (Error Err = save(SummaryIndexFiles[Task], J.SummaryIndexPath))
196 return Err;
197 }
198 if (OnIndexWriteCb)
199 OnIndexWriteCb(J.SummaryIndexPath.str());
200
201 if (ShouldEmitImportFiles)
202 if (Error Err = save(join(J.ImportsFilesList, "\n"), J.ImportsPath))
203 return Err;
204
205 if (!SaveTemps) {
206 if (!J.Cached)
207 addToCleanup(J.NativeObjectPath.str());
208 if (!ShouldEmitIndexFiles)
209 addToCleanup(J.SummaryIndexPath.str());
210 if (!ShouldEmitImportFiles)
211 addToCleanup(J.ImportsPath.str());
212 }
213 return Error::success();
214}
215
216// Derive a set of Clang options that will be shared/common for all DTLTO
217// backend compilations.
218void lto::DTLTO::buildCommonRemoteCompilerOptions() {
219 const lto::Config &C = getConfig();
220 auto &Ops = DistributorParams.CodegenOptions;
221
222 Ops.push_back(Saver.save("-O" + Twine(C.OptLevel)));
223
224 if (C.Options.EmitAddrsig)
225 Ops.push_back("-faddrsig");
226 if (C.Options.FunctionSections)
227 Ops.push_back("-ffunction-sections");
228 if (C.Options.DataSections)
229 Ops.push_back("-fdata-sections");
230 if (C.PTO.LoopInterchange)
231 Ops.push_back("-floop-interchange");
232
233 if (C.RelocModel == Reloc::PIC_)
234 // Clang doesn't have -fpic for all triples.
235 if (!DistributorParams.TargetTriple.isOSBinFormatCOFF())
236 Ops.push_back("-fpic");
237
238 // Turn on/off warnings about profile cfg mismatch (default on)
239 // --lto-pgo-warn-mismatch.
240 if (!C.PGOWarnMismatch) {
241 Ops.push_back("-mllvm");
242 Ops.push_back("-no-pgo-warn-mismatch");
243 }
244
245 // Enable sample-based profile guided optimizations.
246 // Sample profile file path --lto-sample-profile=<value>.
247 if (!C.SampleProfile.empty()) {
248 Ops.push_back(Saver.save("-fprofile-sample-use=" + Twine(C.SampleProfile)));
249 DistributorParams.CommonInputs.insert(C.SampleProfile);
250 }
251
252 // We don't know which of options will be used by Clang.
253 Ops.push_back("-Wno-unused-command-line-argument");
254
255 // Forward any supplied options.
256 if (!DistributorParams.RemoteCompilerArgs.empty())
257 for (auto &a : DistributorParams.RemoteCompilerArgs)
258 Ops.push_back(a);
259}
260
261// Initializes DTLTO state and prepares a job for each ThinLTO module.
262Error lto::DTLTO::prepareDtltoJobs() {
263 auto &ModuleMap =
264 ThinLTO.ModulesToCompile ? *ThinLTO.ModulesToCompile : ThinLTO.ModuleMap;
265
266 InputModuleIDsToExtract.clear();
267
268 if (ModuleMap.empty())
269 return Error::success();
270
271 Jobs.resize(ModuleMap.size());
272
273 for (auto [I, Mod] : enumerate(ModuleMap))
274 if (Error E = prepareDtltoJob(Mod.first, ThinLTOTaskOffset + I))
275 return E;
276
277 return Error::success();
278}
279
280// Runs the DTLTO code generation phase. Must be invoked after thinLink().
281Error lto::DTLTO::performCodegen() {
282 if (Jobs.empty())
283 return Error::success();
284 // Build common remote compiler options.
285 buildCommonRemoteCompilerOptions();
286
287 DistributionDriver Distributor(DistributorParams, Jobs, SaveTemps,
288 [&](StringRef S) { addToCleanup(S); });
289
290 if (CachedJobs.load() < Jobs.size()) {
291 if (Error E = Distributor())
292 return E;
293 }
294 return Error::success();
295}
296
297// Adds compiled object files to the link for each non-cached job.
298Error lto::DTLTO::addObjectFilesToLink() {
299 TimeTraceScope FilesScope("Add DTLTO files to the link");
300 for (auto &Job : Jobs) {
301 if (!Job.CacheKey.empty() && Job.Cached) {
302 assert(Cache.isValid());
303 continue;
304 }
305 // Load the native object from a file into a memory buffer
306 // and store its contents in the output buffer.
307 auto ObjFileMbOrErr =
309 /*RequiresNullTerminator=*/false);
310 if (std::error_code EC = ObjFileMbOrErr.getError())
312 BCError + "cannot open native object file: " + Job.NativeObjectPath +
313 ": " + EC.message(),
315
316 MemoryBufferRef ObjFileMbRef = ObjFileMbOrErr->get()->getMemBufferRef();
317 if (Cache.isValid()) {
318 // Cache hits are taken care of earlier. At this point, we could only
319 // have cache misses.
321 // Obtain a file stream for a storing a cache entry.
322 auto CachedFileStreamOrErr = Job.CacheAddStream(Job.Task, Job.ModuleID);
323 if (!CachedFileStreamOrErr)
324 return joinErrors(
325 CachedFileStreamOrErr.takeError(),
327 "Cannot get a cache file stream: %s",
329 // Store a file buffer into the cache stream.
330 auto &CacheStream = *(CachedFileStreamOrErr->get());
331 *(CacheStream.OS) << ObjFileMbRef.getBuffer();
332 if (Error Err = CacheStream.commit())
333 return Err;
334 } else {
335 if (AddBuffer) {
336 AddBuffer(Job.Task, Job.ModuleID, std::move(ObjFileMbOrErr.get()));
337 } else {
338 auto StreamOrErr = AddStreamFunc(Job.Task, Job.ModuleID);
339 if (Error Err = StreamOrErr.takeError())
340 return Err;
341 auto &Stream = *StreamOrErr->get();
342 *Stream.OS << ObjFileMbRef.getBuffer();
343 if (Error Err = Stream.commit())
344 return Err;
345 }
346 }
347 }
348 return Error::success();
349}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define LLVM_ABI
Definition Compiler.h:215
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
#define I(x, y, z)
Definition MD5.cpp:57
if(PassOpts->AAPipeline)
Provides a library for accessing information about this process and other processes on the operating ...
This file contains some templates that are useful if you are working with the STL at all.
This file defines the make_scope_exit function, which executes user-defined cleanup logic at scope ex...
This file defines the SmallString class.
This file contains some functions that are useful when dealing with strings.
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
static ErrorSuccess success()
Create a success value.
Definition Error.h:336
StringRef getBuffer() const
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFile(const Twine &Filename, bool IsText=false, bool RequiresNullTerminator=true, bool IsVolatile=false, std::optional< Align > Alignment=std::nullopt)
Open the specified file as a MemoryBuffer, returning a new MemoryBuffer if successful,...
constexpr const char * data() const
Get a pointer to the start of the string (which may not be null terminated).
Definition StringRef.h:138
The TimeTraceScope is a helper class to call the begin and end functions of the time trace profiler.
virtual Error run(AddStreamFn AddStream, FileCache Cache={}) override
Runs the DTLTO pipeline.
Definition DTLTO.cpp:109
void waitForCleanup() override
Wait for LTO cleanup.
Definition DTLTO.cpp:75
Config & getConfig()
Definition DTLTO.h:123
struct llvm::lto::LTO::RegularLTOState RegularLTO
virtual void cleanup()
Definition LTO.cpp:711
Config Conf
Definition LTO.h:466
struct llvm::lto::LTO::ThinLTOState ThinLTO
unsigned getMaxTasks() const
Returns an upper bound on the number of tasks that the client may expect.
Definition LTO.cpp:1272
virtual Error run(AddStreamFn AddStream, FileCache Cache={})
Runs the LTO pipeline.
Definition LTO.cpp:1323
static LLVM_ABI Pid getProcessId()
Get the process's identifier.
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
LLVM_ABI StringRef stem(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get stem.
Definition Path.cpp:596
LLVM_ABI StringRef parent_path(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get parent path.
Definition Path.cpp:478
LLVM_ABI void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")
Append to path.
Definition Path.cpp:467
This is an optimization pass for GlobalISel generic memory operations.
ThreadPoolStrategy hardware_concurrency(unsigned ThreadCount=0)
Returns a default thread strategy where all available hardware resources are to be used,...
Definition Threading.h:190
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
Definition STLExtras.h:2554
LLVM_ABI std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Definition Error.cpp:94
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition Error.h:1321
LLVM_ABI void timeTraceProfilerFinishThread()
Finish a time trace profiler running on a worker thread.
Error joinErrors(Error E1, Error E2)
Concatenate errors.
Definition Error.h:442
Error make_error(ArgTs &&... Args)
Make a Error instance representing failure using the given error info type.
Definition Error.h:340
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
@ Mod
The access may modify the value stored in memory.
Definition ModRef.h:34
std::string join(IteratorT Begin, IteratorT End, StringRef Separator)
Joins the strings in the range [Begin, End), adding Separator between the elements.
SingleThreadExecutor DefaultThreadPool
Definition ThreadPool.h:262
std::function< Expected< std::unique_ptr< CachedFileStream > >( unsigned Task, const Twine &ModuleName)> AddStreamFn
This type defines the callback to add a file that is generated on the fly.
Definition Caching.h:58
std::string itostr(int64_t X)
This type represents a file cache system that manages caching of files.
Definition Caching.h:84
LTO configuration.
Definition Config.h:43
std::function< std::string &(size_t Task)> GetCacheKeyOutputString
Called by WriteIndexesThinBackend when it needs to store a bitcode module's cache key.
Definition Config.h:312
std::function< std::vector< std::string > &(size_t Task)> GetImportsListOutputArray
Called by WriteIndexesThinBackend when it needs to store a bitcode module's imports list.
Definition Config.h:307
std::function< std::unique_ptr< raw_pwrite_stream >(size_t Task)> GetSummaryIndexOutputStream
Called by WriteIndexesThinBackend when it needs to write a bitcode module's summary index.
Definition Config.h:301
AddStreamFn CacheAddStream
Definition DTLTO.h:164
StringRef NativeObjectPath
Definition DTLTO.h:154
StringRef ModuleID
Definition DTLTO.h:152
std::string CacheKey
Definition DTLTO.h:162