Skip to content

Commit 17165b8

Browse files
committed
[LLD][COFF] Prefetch inputs early on to improve link times
1 parent 86cbb36 commit 17165b8

File tree

6 files changed

+54
-1
lines changed

6 files changed

+54
-1
lines changed

lld/COFF/Driver.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,8 @@ static std::future<MBErrPair> createFutureForFile(std::string path) {
164164
/*RequiresNullTerminator=*/false);
165165
if (!mbOrErr)
166166
return MBErrPair{nullptr, mbOrErr.getError()};
167+
// Prefetch memory pages in the background as we will need them soon enough.
168+
(*mbOrErr)->willNeedIfMmap();
167169
return MBErrPair{std::move(*mbOrErr), std::error_code()};
168170
});
169171
}
@@ -337,8 +339,12 @@ void LinkerDriver::enqueuePath(StringRef path, bool wholeArchive, bool lazy) {
337339
auto retryMb = MemoryBuffer::getFile(*retryPath, /*IsText=*/false,
338340
/*RequiresNullTerminator=*/false);
339341
ec = retryMb.getError();
340-
if (!ec)
342+
if (!ec) {
341343
mb = std::move(*retryMb);
344+
// Prefetch memory pages in the background as we will need them soon
345+
// enough.
346+
mb->willNeedIfMmap();
347+
}
342348
} else {
343349
// We've already handled this file.
344350
return;

llvm/include/llvm/Support/FileSystem.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1310,6 +1310,7 @@ class mapped_file_region {
13101310

13111311
LLVM_ABI void unmapImpl();
13121312
LLVM_ABI void dontNeedImpl();
1313+
LLVM_ABI void willNeedImpl();
13131314

13141315
LLVM_ABI std::error_code init(sys::fs::file_t FD, uint64_t Offset,
13151316
mapmode Mode);
@@ -1341,6 +1342,7 @@ class mapped_file_region {
13411342
copyFrom(mapped_file_region());
13421343
}
13431344
void dontNeed() { dontNeedImpl(); }
1345+
void willNeed() { willNeedImpl(); }
13441346

13451347
LLVM_ABI size_t size() const;
13461348
LLVM_ABI char *data() const;

llvm/include/llvm/Support/MemoryBuffer.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,11 @@ class LLVM_ABI MemoryBuffer {
8383
/// function should not be called on a writable buffer.
8484
virtual void dontNeedIfMmap() {}
8585

86+
/// Mark the buffer as to-be-used in a near future. This shall trigger OS
87+
/// prefetching from the storage device and into memory, if possible.
88+
/// This should be use purely as an read optimization.
89+
virtual void willNeedIfMmap() {}
90+
8691
/// Open the specified file as a MemoryBuffer, returning a new MemoryBuffer
8792
/// if successful, otherwise returning null.
8893
///

llvm/lib/Support/MemoryBuffer.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ class MemoryBufferMMapFile : public MB {
243243
}
244244

245245
void dontNeedIfMmap() override { MFR.dontNeed(); }
246+
void willNeedIfMmap() override { MFR.willNeed(); }
246247
};
247248
} // namespace
248249

llvm/lib/Support/Unix/Path.inc

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -900,6 +900,19 @@ void mapped_file_region::dontNeedImpl() {
900900
#endif
901901
}
902902

903+
void mapped_file_region::willNeedImpl() {
904+
assert(Mode == mapped_file_region::readonly);
905+
if (!Mapping)
906+
return;
907+
#if defined(__MVS__) || defined(_AIX)
908+
// If we don't have madvise, or it isn't beneficial, treat this as a no-op.
909+
#elif defined(POSIX_MADV_WILLNEED)
910+
::posix_madvise(Mapping, Size, POSIX_MADV_WILLNEED);
911+
#else
912+
::madvise(Mapping, Size, MADV_WILLNEED);
913+
#endif
914+
}
915+
903916
int mapped_file_region::alignment() { return Process::getPageSizeEstimate(); }
904917

905918
std::error_code detail::directory_iterator_construct(detail::DirIterState &it,

llvm/lib/Support/Windows/Path.inc

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1023,6 +1023,32 @@ void mapped_file_region::unmapImpl() {
10231023

10241024
void mapped_file_region::dontNeedImpl() {}
10251025

1026+
void mapped_file_region::willNeedImpl() {
1027+
#if (_WIN32_WINNT < _WIN32_WINNT_WIN8)
1028+
typedef struct _WIN32_MEMORY_RANGE_ENTRY {
1029+
PVOID VirtualAddress;
1030+
SIZE_T NumberOfBytes;
1031+
} WIN32_MEMORY_RANGE_ENTRY, *PWIN32_MEMORY_RANGE_ENTRY;
1032+
#endif
1033+
1034+
HMODULE kernelM = llvm::sys::windows::loadSystemModuleSecure(L"kernel32.dll");
1035+
if (kernelM) {
1036+
// PrefetchVirtualMemory is only available on Windows 8 and later. Since we
1037+
// still support compilation on Windows 7, we load the function dynamically.
1038+
typedef BOOL(WINAPI * PrefetchVirtualMemory_t)(
1039+
HANDLE hProcess, ULONG_PTR NumberOfEntries,
1040+
_In_reads_(NumberOfEntries) PWIN32_MEMORY_RANGE_ENTRY VirtualAddresses,
1041+
ULONG Flags);
1042+
static const auto pfnPrefetchVirtualMemory =
1043+
(PrefetchVirtualMemory_t)::GetProcAddress(kernelM,
1044+
"PrefetchVirtualMemory");
1045+
if (pfnPrefetchVirtualMemory) {
1046+
WIN32_MEMORY_RANGE_ENTRY Range{Mapping, Size};
1047+
pfnPrefetchVirtualMemory(::GetCurrentProcess(), 1, &Range, 0);
1048+
}
1049+
}
1050+
}
1051+
10261052
std::error_code mapped_file_region::sync() const {
10271053
if (!::FlushViewOfFile(Mapping, Size))
10281054
return mapWindowsError(GetLastError());

0 commit comments

Comments
 (0)