Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion lld/COFF/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ static std::future<MBErrPair> createFutureForFile(std::string path) {
/*RequiresNullTerminator=*/false);
if (!mbOrErr)
return MBErrPair{nullptr, mbOrErr.getError()};
// Prefetch memory pages in the background as we will need them soon enough.
(*mbOrErr)->willNeedIfMmap();
return MBErrPair{std::move(*mbOrErr), std::error_code()};
});
}
Expand Down Expand Up @@ -337,8 +339,12 @@ void LinkerDriver::enqueuePath(StringRef path, bool wholeArchive, bool lazy) {
auto retryMb = MemoryBuffer::getFile(*retryPath, /*IsText=*/false,
/*RequiresNullTerminator=*/false);
ec = retryMb.getError();
if (!ec)
if (!ec) {
mb = std::move(*retryMb);
// Prefetch memory pages in the background as we will need them soon
// enough.
mb->willNeedIfMmap();
}
} else {
// We've already handled this file.
return;
Expand Down
2 changes: 2 additions & 0 deletions llvm/include/llvm/Support/FileSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -1310,6 +1310,7 @@ class mapped_file_region {

LLVM_ABI void unmapImpl();
LLVM_ABI void dontNeedImpl();
LLVM_ABI void willNeedImpl();

LLVM_ABI std::error_code init(sys::fs::file_t FD, uint64_t Offset,
mapmode Mode);
Expand Down Expand Up @@ -1341,6 +1342,7 @@ class mapped_file_region {
copyFrom(mapped_file_region());
}
void dontNeed() { dontNeedImpl(); }
void willNeed() { willNeedImpl(); }

LLVM_ABI size_t size() const;
LLVM_ABI char *data() const;
Expand Down
5 changes: 5 additions & 0 deletions llvm/include/llvm/Support/MemoryBuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,11 @@ class LLVM_ABI MemoryBuffer {
/// function should not be called on a writable buffer.
virtual void dontNeedIfMmap() {}

/// Mark the buffer as to-be-used in a near future. This shall trigger OS
/// prefetching from the storage device and into memory, if possible.
/// This should be use purely as an read optimization.
virtual void willNeedIfMmap() {}

/// Open the specified file as a MemoryBuffer, returning a new MemoryBuffer
/// if successful, otherwise returning null.
///
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Support/MemoryBuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ class MemoryBufferMMapFile : public MB {
}

void dontNeedIfMmap() override { MFR.dontNeed(); }
void willNeedIfMmap() override { MFR.willNeed(); }
};
} // namespace

Expand Down
13 changes: 13 additions & 0 deletions llvm/lib/Support/Unix/Path.inc
Original file line number Diff line number Diff line change
Expand Up @@ -900,6 +900,19 @@ void mapped_file_region::dontNeedImpl() {
#endif
}

void mapped_file_region::willNeedImpl() {
assert(Mode == mapped_file_region::readonly);
if (!Mapping)
return;
#if defined(__MVS__) || defined(_AIX)
// If we don't have madvise, or it isn't beneficial, treat this as a no-op.
#elif defined(POSIX_MADV_WILLNEED)
::posix_madvise(Mapping, Size, POSIX_MADV_WILLNEED);
#else
::madvise(Mapping, Size, MADV_WILLNEED);
#endif
}

int mapped_file_region::alignment() { return Process::getPageSizeEstimate(); }

std::error_code detail::directory_iterator_construct(detail::DirIterState &it,
Expand Down
26 changes: 26 additions & 0 deletions llvm/lib/Support/Windows/Path.inc
Original file line number Diff line number Diff line change
Expand Up @@ -1023,6 +1023,32 @@ void mapped_file_region::unmapImpl() {

void mapped_file_region::dontNeedImpl() {}

void mapped_file_region::willNeedImpl() {
#if (_WIN32_WINNT < _WIN32_WINNT_WIN8)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have many of these cases? I wonder if we should sink this into LLVM with a check for the type definition.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we're dlopen'ing and rolling our own function prototype anyway below, maybe we should just define this struct unconditionally (with a name that doesn't clash with the windows header)?

typedef struct _WIN32_MEMORY_RANGE_ENTRY {
PVOID VirtualAddress;
SIZE_T NumberOfBytes;
} WIN32_MEMORY_RANGE_ENTRY, *PWIN32_MEMORY_RANGE_ENTRY;
#endif

HMODULE kernelM = llvm::sys::windows::loadSystemModuleSecure(L"kernel32.dll");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is where the version is likely more useful. In the case of the minimum deployment version being >7, we should prefer static linking IMO. But, I know that is more challenging and potentially not as valuable to invest in, so more of a passing comment.

if (kernelM) {
// PrefetchVirtualMemory is only available on Windows 8 and later. Since we
// still support compilation on Windows 7, we load the function dynamically.
typedef BOOL(WINAPI * PrefetchVirtualMemory_t)(
HANDLE hProcess, ULONG_PTR NumberOfEntries,
_In_reads_(NumberOfEntries) PWIN32_MEMORY_RANGE_ENTRY VirtualAddresses,
ULONG Flags);
static const auto pfnPrefetchVirtualMemory =
(PrefetchVirtualMemory_t)::GetProcAddress(kernelM,
"PrefetchVirtualMemory");
if (pfnPrefetchVirtualMemory) {
WIN32_MEMORY_RANGE_ENTRY Range{Mapping, Size};
pfnPrefetchVirtualMemory(::GetCurrentProcess(), 1, &Range, 0);
}
}
}

std::error_code mapped_file_region::sync() const {
if (!::FlushViewOfFile(Mapping, Size))
return mapWindowsError(GetLastError());
Expand Down