Skip to content

Commit a8eeead

Browse files
committed
Multi-thread i/o in background.
1 parent 02fb145 commit a8eeead

File tree

1 file changed

+73
-31
lines changed

1 file changed

+73
-31
lines changed

lld/MachO/Driver.cpp

Lines changed: 73 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -290,27 +290,26 @@ typedef struct {
290290
const char *start;
291291
size_t size;
292292
} DeferredFile;
293+
typedef std::vector<DeferredFile> DeferredFiles;
294+
295+
#ifndef _WIN32
296+
typedef struct {
297+
DeferredFiles deferred;
298+
size_t counter, total, pageSize;
299+
pthread_mutex_t mutex;
300+
} PageInState;
293301

294302
// Most input files have been mapped but not yet paged in.
295303
// This code forces the page-ins on multiple threads so
296304
// the process is not stalled waiting on disk buffer i/o.
297-
static void multiThreadedPageIn(std::vector<DeferredFile> &deferred) {
298-
#ifndef _WIN32
305+
static void multiThreadedPageInBackground(PageInState *state) {
299306
#define MaxReadThreads 200
300-
typedef struct {
301-
std::vector<DeferredFile> &deferred;
302-
size_t counter, total, pageSize;
303-
pthread_mutex_t mutex;
304-
} PageInState;
305-
PageInState state = {deferred, 0, 0,
306-
llvm::sys::Process::getPageSizeEstimate(),
307-
pthread_mutex_t()};
308307
static size_t totalBytes;
309308

310309
pthread_t running[MaxReadThreads];
311310
if (config->readThreads > MaxReadThreads)
312311
config->readThreads = MaxReadThreads;
313-
pthread_mutex_init(&state.mutex, NULL);
312+
pthread_mutex_init(&state->mutex, nullptr);
314313

315314
for (int t = 0; t < config->readThreads; t++)
316315
pthread_create(
@@ -336,20 +335,49 @@ static void multiThreadedPageIn(std::vector<DeferredFile> &deferred) {
336335
state.total += t; // Avoids the loop being optimised out.
337336
}
338337
},
339-
&state);
338+
state);
340339

341340
for (int t = 0; t < config->readThreads; t++)
342341
pthread_join(running[t], nullptr);
343342

344-
pthread_mutex_destroy(&state.mutex);
343+
pthread_mutex_destroy(&state->mutex);
345344
if (getenv("LLD_MULTI_THREAD_PAGE"))
346-
printf("multiThreadedPageIn %ld/%ld\n", totalBytes, deferred.size());
345+
printf("multiThreadedPageIn %ld/%ld\n", totalBytes, state->deferred.size());
346+
}
347+
#endif
348+
349+
static void multiThreadedPageIn(DeferredFiles deferred) {
350+
#ifndef _WIN32
351+
static pthread_t running;
352+
static pthread_mutex_t busy;
353+
354+
if (running)
355+
pthread_join(running, nullptr);
356+
else
357+
pthread_mutex_init(&busy, nullptr);
358+
359+
PageInState *state =
360+
new PageInState{deferred, 0, 0, llvm::sys::Process::getPageSizeEstimate(),
361+
pthread_mutex_t()};
362+
363+
pthread_mutex_lock(&busy);
364+
pthread_create(
365+
&running, nullptr,
366+
[](void *ptr) -> void * {
367+
PageInState *state = (PageInState *)ptr;
368+
multiThreadedPageInBackground(state);
369+
pthread_mutex_unlock(&busy);
370+
delete state;
371+
return nullptr;
372+
},
373+
state);
347374
#endif
348375
}
349376

350377
static InputFile *processFile(std::optional<MemoryBufferRef> buffer,
351-
StringRef path, LoadType loadType,
352-
bool isLazy = false, bool isExplicit = true,
378+
DeferredFiles *archiveContents, StringRef path,
379+
LoadType loadType, bool isLazy = false,
380+
bool isExplicit = true,
353381
bool isBundleLoader = false,
354382
bool isForceHidden = false) {
355383
if (!buffer)
@@ -431,7 +459,6 @@ static InputFile *processFile(std::optional<MemoryBufferRef> buffer,
431459
// we already found that it contains an ObjC symbol.
432460
if (readFile(path)) {
433461
Error e = Error::success();
434-
std::vector<DeferredFile> deferredFiles;
435462
for (const object::Archive::Child &c : file->getArchive().children(e)) {
436463
Expected<MemoryBufferRef> mb = c.getMemoryBufferRef();
437464
if (!mb) {
@@ -445,9 +472,10 @@ static InputFile *processFile(std::optional<MemoryBufferRef> buffer,
445472
continue;
446473
}
447474

448-
deferredFiles.push_back({path, isLazy, std::nullopt,
449-
mb->getBuffer().data(),
450-
mb->getBuffer().size()});
475+
if (archiveContents)
476+
archiveContents->push_back({path, isLazy, std::nullopt,
477+
mb->getBuffer().data(),
478+
mb->getBuffer().size()});
451479
if (!hasObjCSection(*mb))
452480
continue;
453481
if (Error e = file->fetch(c, "-ObjC"))
@@ -457,11 +485,10 @@ static InputFile *processFile(std::optional<MemoryBufferRef> buffer,
457485
if (e)
458486
error(toString(file) +
459487
": Archive::children failed: " + toString(std::move(e)));
460-
if (config->readThreads && deferredFiles.size() > 1)
461-
multiThreadedPageIn(deferredFiles);
462488
}
463489
}
464-
file->addLazySymbols();
490+
if (!archiveContents || archiveContents->empty())
491+
file->addLazySymbols();
465492
loadedArchives[path] = ArchiveFileInfo{file, isCommandLineLoad};
466493
newFile = file;
467494
break;
@@ -516,18 +543,17 @@ static InputFile *addFile(StringRef path, LoadType loadType,
516543
bool isLazy = false, bool isExplicit = true,
517544
bool isBundleLoader = false,
518545
bool isForceHidden = false) {
519-
return processFile(readFile(path), path, loadType, isLazy, isExplicit,
520-
isBundleLoader, isForceHidden);
546+
return processFile(readFile(path), nullptr, path, loadType, isLazy,
547+
isExplicit, isBundleLoader, isForceHidden);
521548
}
522549

523-
static void deferFile(StringRef path, bool isLazy,
524-
std::vector<DeferredFile> &deferred) {
550+
static void deferFile(StringRef path, bool isLazy, DeferredFiles &deferred) {
525551
std::optional<MemoryBufferRef> buffer = readFile(path);
526552
if (config->readThreads)
527553
deferred.push_back({path, isLazy, buffer, buffer->getBuffer().data(),
528554
buffer->getBuffer().size()});
529555
else
530-
processFile(buffer, path, LoadType::CommandLine, isLazy);
556+
processFile(buffer, nullptr, path, LoadType::CommandLine, isLazy);
531557
}
532558

533559
static std::vector<StringRef> missingAutolinkWarnings;
@@ -654,7 +680,7 @@ void macho::resolveLCLinkerOptions() {
654680
}
655681

656682
static void addFileList(StringRef path, bool isLazy,
657-
std::vector<DeferredFile> &deferredFiles) {
683+
DeferredFiles &deferredFiles) {
658684
std::optional<MemoryBufferRef> buffer = readFile(path);
659685
if (!buffer)
660686
return;
@@ -1312,7 +1338,7 @@ static void createFiles(const InputArgList &args) {
13121338
bool isLazy = false;
13131339
// If we've processed an opening --start-lib, without a matching --end-lib
13141340
bool inLib = false;
1315-
std::vector<DeferredFile> deferredFiles;
1341+
DeferredFiles deferredFiles;
13161342

13171343
for (const Arg *arg : args) {
13181344
const Option &opt = arg->getOption();
@@ -1390,8 +1416,24 @@ static void createFiles(const InputArgList &args) {
13901416

13911417
if (config->readThreads) {
13921418
multiThreadedPageIn(deferredFiles);
1419+
1420+
DeferredFiles archiveContents;
1421+
std::vector<ArchiveFile *> archives;
13931422
for (auto &file : deferredFiles)
1394-
processFile(file.buffer, file.path, LoadType::CommandLine, file.isLazy);
1423+
if (ArchiveFile *archive = dyn_cast<ArchiveFile>(
1424+
processFile(file.buffer, &archiveContents, file.path,
1425+
LoadType::CommandLine, file.isLazy)))
1426+
archives.push_back(archive);
1427+
1428+
if (!archiveContents.empty()) {
1429+
multiThreadedPageIn(archiveContents);
1430+
for (auto *archive : archives)
1431+
archive->addLazySymbols();
1432+
}
1433+
1434+
// flush threads
1435+
deferredFiles.clear();
1436+
multiThreadedPageIn(deferredFiles);
13951437
}
13961438
}
13971439

0 commit comments

Comments
 (0)