[lld] [lld][MachO]Multi-threaded i/o. Twice as fast linking a large project. (PR #147134)

John Holdsworth via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 8 23:01:36 PDT 2025


================
@@ -282,11 +283,103 @@ 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);
+typedef struct {
+  StringRef path;
+  bool isLazy;
+  std::optional<MemoryBufferRef> buffer;
+  const char *start;
+  size_t size;
+} DeferredFile;
+typedef std::vector<DeferredFile> DeferredFiles;
+
+#ifndef _WIN32
+typedef struct {
+  DeferredFiles deferred;
+  size_t counter, total, pageSize;
+  pthread_mutex_t mutex;
+} PageInState;
+
+// 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.
+static void multiThreadedPageInBackground(PageInState *state) {
+#define MaxReadThreads 200
+  static size_t totalBytes;
+
+  pthread_t running[MaxReadThreads];
+  if (config->readThreads > MaxReadThreads)
+    config->readThreads = MaxReadThreads;
+  pthread_mutex_init(&state->mutex, nullptr);
+
+  for (int t = 0; t < config->readThreads; t++)
+    pthread_create(
+        &running[t], nullptr,
+        [](void *ptr) -> void * {
+          PageInState &state = *(PageInState *)ptr;
+          while (true) {
+            pthread_mutex_lock(&state.mutex);
+            if (state.counter >= state.deferred.size()) {
+              pthread_mutex_unlock(&state.mutex);
+              return nullptr;
+            }
+            DeferredFile &file = state.deferred[state.counter];
+            state.counter += 1;
+            pthread_mutex_unlock(&state.mutex);
+
+            const char *page = file.start, *end = page + file.size;
+            totalBytes += end - page;
+
+            int t = 0; // Reference each page to load it into memory.
+            for (; page < end; page += state.pageSize)
+              t += *page;
+            state.total += t; // Avoids the loop being optimised out.
+          }
+        },
+        state);
+
+  for (int t = 0; t < config->readThreads; t++)
+    pthread_join(running[t], nullptr);
+
+  pthread_mutex_destroy(&state->mutex);
+  if (getenv("LLD_MULTI_THREAD_PAGE"))
+    printf("multiThreadedPageIn %ld/%ld\n", totalBytes, state->deferred.size());
+}
+#endif
+
+static void multiThreadedPageIn(DeferredFiles deferred) {
+#ifndef _WIN32
+  static pthread_t running;
+  static pthread_mutex_t busy;
+
+  if (running)
+    pthread_join(running, nullptr);
+  else
+    pthread_mutex_init(&busy, nullptr);
+
+  PageInState *state =
+      new PageInState{deferred, 0, 0, llvm::sys::Process::getPageSizeEstimate(),
+                      pthread_mutex_t()};
+
+  pthread_mutex_lock(&busy);
+  pthread_create(
+      &running, nullptr,
+      [](void *ptr) -> void * {
+        PageInState *state = (PageInState *)ptr;
+        multiThreadedPageInBackground(state);
+        pthread_mutex_unlock(&busy);
+        delete state;
+        return nullptr;
+      },
+      state);
----------------
johnno1962 wrote:

And windows now builds 👍 

https://github.com/llvm/llvm-project/pull/147134


More information about the llvm-commits mailing list