[lld] [lld][MachO]Multi-threaded i/o. Twice as fast linking a large project. (PR #147134)
Daniel RodrÃguez Troitiño via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 18 12:51:31 PDT 2025
================
@@ -282,11 +284,83 @@ static void saveThinArchiveToRepro(ArchiveFile const *file) {
": Archive::children failed: " + toString(std::move(e)));
}
-static InputFile *addFile(StringRef path, LoadType loadType,
- bool isLazy = false, bool isExplicit = true,
- bool isBundleLoader = false,
- bool isForceHidden = false) {
- std::optional<MemoryBufferRef> buffer = readFile(path);
+class DeferredFile {
+public:
+ DeferredFile(StringRef path, bool isLazy, MemoryBufferRef buffer)
+ : path(path), isLazy(isLazy), buffer(buffer) {}
+ StringRef path;
+ bool isLazy;
+ MemoryBufferRef buffer;
+};
+using DeferredFiles = std::vector<DeferredFile>;
+
+// Most input files have been mapped but not yet paged in.
+// This code forces the page-ins on multiple threads so
+// the process is not stalled waiting on disk buffer i/o.
+void multiThreadedPageInBackground(const DeferredFiles &deferred) {
+ static const size_t pageSize = Process::getPageSizeEstimate();
+ static size_t totalBytes = 0;
+ std::atomic_int index = 0;
+
+ parallelFor(0, config->readThreads, [&](size_t I) {
+ while (true) {
+ int localIndex = index.fetch_add(1);
+ if (localIndex >= (int)deferred.size())
+ break;
+ const StringRef &buff = deferred[localIndex].buffer.getBuffer();
+ totalBytes += buff.size();
+
+ // Reference all file's mmap'd pages to load them into memory.
+ for (const char *page = buff.data(), *end = page + buff.size();
+ page < end; page += pageSize)
+ LLVM_ATTRIBUTE_UNUSED volatile char t = *page;
+ }
+ });
+
+ if (getenv("LLD_MULTI_THREAD_PAGE"))
+ llvm::dbgs() << "multiThreadedPageIn " << totalBytes << "/"
+ << deferred.size() << "\n";
+}
+
+static void multiThreadedPageIn(const DeferredFiles &deferred) {
+ static std::deque<std::unique_ptr<DeferredFiles>> queue;
+ static std::thread *running;
+ static std::mutex mutex;
+
+ mutex.lock();
+ if (running && (queue.empty() || deferred.empty())) {
+ mutex.unlock();
+ running->join();
+ mutex.lock();
+ delete running;
+ running = nullptr;
+ }
+
+ if (!deferred.empty()) {
+ queue.emplace_back(
+ std::unique_ptr<DeferredFiles>(new DeferredFiles(deferred)));
----------------
drodriguez wrote:
This can leave the `unique_ptr` in an invalid state. One needs to use `make_unique`.
```suggestion
queue.emplace_back(std::make_unique<DeferredFiles>(deferred));
```
https://github.com/llvm/llvm-project/pull/147134
More information about the llvm-commits
mailing list