@@ -283,6 +283,70 @@ static void saveThinArchiveToRepro(ArchiveFile const *file) {
283
283
" : Archive::children failed: " + toString (std::move (e)));
284
284
}
285
285
286
+ typedef struct {
287
+ StringRef path;
288
+ bool isLazy;
289
+ std::optional<MemoryBufferRef> buffer;
290
+ const char *start;
291
+ size_t size;
292
+ } DeferredFile;
293
+
294
+ // Most input files have been mapped but not yet paged in.
295
+ // This code forces the page-ins on multiple threads so
296
+ // the process is not stalled waiting on disk buffer i/o.
297
+ static void multiThreadedPageIn (std::vector<DeferredFile> &deferred) {
298
+ #ifndef _WIN32
299
+ #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 ()};
308
+ static size_t totalBytes;
309
+
310
+ pthread_t running[MaxReadThreads];
311
+ if (config->readThreads > MaxReadThreads)
312
+ config->readThreads = MaxReadThreads;
313
+ pthread_mutex_init (&state.mutex , NULL );
314
+
315
+ for (int t = 0 ; t < config->readThreads ; t++)
316
+ pthread_create (
317
+ &running[t], nullptr ,
318
+ [](void *ptr) -> void * {
319
+ PageInState &state = *(PageInState *)ptr;
320
+ while (true ) {
321
+ pthread_mutex_lock (&state.mutex );
322
+ if (state.counter >= state.deferred .size ()) {
323
+ pthread_mutex_unlock (&state.mutex );
324
+ return nullptr ;
325
+ }
326
+ DeferredFile &file = state.deferred [state.counter ];
327
+ state.counter += 1 ;
328
+ pthread_mutex_unlock (&state.mutex );
329
+
330
+ const char *page = file.start , *end = page + file.size ;
331
+ totalBytes += end - page;
332
+
333
+ int t = 0 ; // Reference each page to load it into memory.
334
+ for (; page < end; page += state.pageSize )
335
+ t += *page;
336
+ state.total += t; // Avoids the loop being optimised out.
337
+ }
338
+ },
339
+ &state);
340
+
341
+ for (int t = 0 ; t < config->readThreads ; t++)
342
+ pthread_join (running[t], nullptr );
343
+
344
+ pthread_mutex_destroy (&state.mutex );
345
+ if (getenv (" LLD_MULTI_THREAD_PAGE" ))
346
+ printf (" multiThreadedPageIn %ld/%ld\n " , totalBytes, deferred.size ());
347
+ #endif
348
+ }
349
+
286
350
static InputFile *processFile (std::optional<MemoryBufferRef> buffer,
287
351
StringRef path, LoadType loadType,
288
352
bool isLazy = false , bool isExplicit = true ,
@@ -367,6 +431,7 @@ static InputFile *processFile(std::optional<MemoryBufferRef> buffer,
367
431
// we already found that it contains an ObjC symbol.
368
432
if (readFile (path)) {
369
433
Error e = Error::success ();
434
+ std::vector<DeferredFile> deferredFiles;
370
435
for (const object::Archive::Child &c : file->getArchive ().children (e)) {
371
436
Expected<MemoryBufferRef> mb = c.getMemoryBufferRef ();
372
437
if (!mb) {
@@ -380,6 +445,9 @@ static InputFile *processFile(std::optional<MemoryBufferRef> buffer,
380
445
continue ;
381
446
}
382
447
448
+ deferredFiles.push_back ({path, isLazy, std::nullopt,
449
+ mb->getBuffer ().data (),
450
+ mb->getBuffer ().size ()});
383
451
if (!hasObjCSection (*mb))
384
452
continue ;
385
453
if (Error e = file->fetch (c, " -ObjC" ))
@@ -389,6 +457,8 @@ static InputFile *processFile(std::optional<MemoryBufferRef> buffer,
389
457
if (e)
390
458
error (toString (file) +
391
459
" : Archive::children failed: " + toString (std::move (e)));
460
+ if (config->readThreads && deferredFiles.size () > 1 )
461
+ multiThreadedPageIn (deferredFiles);
392
462
}
393
463
}
394
464
file->addLazySymbols ();
@@ -450,20 +520,15 @@ static InputFile *addFile(StringRef path, LoadType loadType,
450
520
isBundleLoader, isForceHidden);
451
521
}
452
522
453
- typedef struct {
454
- StringRef path;
455
- LoadType loadType;
456
- bool isLazy;
457
- std::optional<MemoryBufferRef> buffer;
458
- } DeferredFile;
459
-
460
- static void deferFile (StringRef path, LoadType loadType, bool isLazy,
523
+ static void deferFile (StringRef path, bool isLazy,
461
524
std::vector<DeferredFile> &deferred) {
462
525
std::optional<MemoryBufferRef> buffer = readFile (path);
463
526
if (config->readThreads )
464
- deferred.push_back ({path, loadType, isLazy, buffer});
527
+ deferred.push_back ({path, isLazy, buffer,
528
+ buffer->getBuffer ().data (),
529
+ buffer->getBuffer ().size ()});
465
530
else
466
- processFile (buffer, path, loadType , isLazy);
531
+ processFile (buffer, path, LoadType::CommandLine , isLazy);
467
532
}
468
533
469
534
static std::vector<StringRef> missingAutolinkWarnings;
@@ -596,7 +661,7 @@ static void addFileList(StringRef path, bool isLazy,
596
661
return ;
597
662
MemoryBufferRef mbref = *buffer;
598
663
for (StringRef path : args::getLines (mbref))
599
- deferFile (rerootPath (path), LoadType::CommandLine, isLazy, deferredFiles);
664
+ deferFile (rerootPath (path), isLazy, deferredFiles);
600
665
}
601
666
602
667
// We expect sub-library names of the form "libfoo", which will match a dylib
@@ -1241,61 +1306,7 @@ static void handleSymbolPatterns(InputArgList &args,
1241
1306
parseSymbolPatternsFile (arg, symbolPatterns);
1242
1307
}
1243
1308
1244
- // Most input files have been mapped but not yet paged in.
1245
- // This code forces the page-ins on multiple threads so
1246
- // the process is not stalled waiting on disk buffer i/o.
1247
- void multiThreadedPageIn (std::vector<DeferredFile> &deferred, int nthreads) {
1248
- #ifndef _WIN32
1249
- #define MaxReadThreads 200
1250
- typedef struct {
1251
- std::vector<DeferredFile> &deferred;
1252
- size_t counter, bytes, total, pageSize;
1253
- pthread_mutex_t mutex;
1254
- } PageInState;
1255
- PageInState state = {
1256
- deferred, 0 , 0 , 0 , llvm::sys::Process::getPageSizeEstimate (),
1257
- pthread_mutex_t ()};
1258
- pthread_mutex_init (&state.mutex , NULL );
1259
-
1260
- pthread_t running[MaxReadThreads];
1261
- if (nthreads > MaxReadThreads)
1262
- nthreads = MaxReadThreads;
1263
-
1264
- for (int t = 0 ; t < nthreads; t++)
1265
- pthread_create (
1266
- &running[t], nullptr ,
1267
- [](void *ptr) -> void * {
1268
- PageInState &state = *(PageInState *)ptr;
1269
- while (true ) {
1270
- pthread_mutex_lock (&state.mutex );
1271
- if (state.counter >= state.deferred .size ()) {
1272
- pthread_mutex_unlock (&state.mutex );
1273
- return nullptr ;
1274
- }
1275
- DeferredFile &file = state.deferred [state.counter ];
1276
- state.counter += 1 ;
1277
- pthread_mutex_unlock (&state.mutex );
1278
-
1279
- const char *page = file.buffer ->getBuffer ().data (),
1280
- *end = page + file.buffer ->getBuffer ().size ();
1281
- state.bytes += end - page;
1282
-
1283
- int t = 0 ; // Reference each page to load it into memory.
1284
- for (; page < end; page += state.pageSize )
1285
- t += *page;
1286
- state.total += t; // Avoids the loop being optimised out.
1287
- }
1288
- },
1289
- &state);
1290
-
1291
- for (int t = 0 ; t < nthreads; t++)
1292
- pthread_join (running[t], nullptr );
1293
-
1294
- pthread_mutex_destroy (&state.mutex );
1295
- #endif
1296
- }
1297
-
1298
- void createFiles (const InputArgList &args) {
1309
+ static void createFiles (const InputArgList &args) {
1299
1310
TimeTraceScope timeScope (" Load input files" );
1300
1311
// This loop should be reserved for options whose exact ordering matters.
1301
1312
// Other options should be handled via filtered() and/or getLastArg().
@@ -1311,8 +1322,7 @@ void createFiles(const InputArgList &args) {
1311
1322
1312
1323
switch (opt.getID ()) {
1313
1324
case OPT_INPUT:
1314
- deferFile (rerootPath (arg->getValue ()), LoadType::CommandLine, isLazy,
1315
- deferredFiles);
1325
+ deferFile (rerootPath (arg->getValue ()), isLazy, deferredFiles);
1316
1326
break ;
1317
1327
case OPT_needed_library:
1318
1328
if (auto *dylibFile = dyn_cast_or_null<DylibFile>(
@@ -1380,9 +1390,9 @@ void createFiles(const InputArgList &args) {
1380
1390
}
1381
1391
1382
1392
if (config->readThreads ) {
1383
- multiThreadedPageIn (deferredFiles, config-> readThreads );
1393
+ multiThreadedPageIn (deferredFiles);
1384
1394
for (auto &file : deferredFiles)
1385
- processFile (file.buffer , file.path , file. loadType , file.isLazy );
1395
+ processFile (file.buffer , file.path , LoadType::CommandLine , file.isLazy );
1386
1396
}
1387
1397
}
1388
1398
0 commit comments