Skip to content

WIP: experimental LoadLibrary monitoring in CoreCLR native runtime #93258

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 13 commits into from
Closed
1 change: 1 addition & 0 deletions src/coreclr/utilcode/longfilepathwrappers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ LoadLibraryExWrapper(
{
LongFile::NormalizeDirectorySeparators(path);


ret = LoadLibraryExW(path.GetUnicode(), hFile, dwFlags);
}

Expand Down
12 changes: 12 additions & 0 deletions src/coreclr/vm/peimagelayout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,10 @@ LoadedImageLayout::LoadedImageLayout(PEImage* pOwner, HRESULT* loadFailure)
#endif // LOGGING

#else
ReportPreloadTime(pOwner->GetPath());

int64_t before = GetPreciseTickCount();

HANDLE hFile = pOwner->GetFileHandle();
INT64 offset = pOwner->GetOffset();

Expand Down Expand Up @@ -580,6 +584,7 @@ LoadedImageLayout::LoadedImageLayout(PEImage* pOwner, HRESULT* loadFailure)
ApplyBaseRelocations(/* relocationMustWriteCopy*/ false);
SetRelocated();
}
ReportActionTime("LOAD_LIBRARY", pOwner->GetPath(), before);
#endif
}

Expand Down Expand Up @@ -1197,7 +1202,12 @@ void* FlatImageLayout::LoadImageByMappingParts(SIZE_T* m_imageParts) const
NativeImageLayout::NativeImageLayout(LPCWSTR fullPath)
{
PVOID loadedImage;

#if TARGET_UNIX
ReportPreloadTime(fullPath);

int64_t before = GetPreciseTickCount();

{
HANDLE fileHandle = WszCreateFile(
fullPath,
Expand All @@ -1215,6 +1225,8 @@ NativeImageLayout::NativeImageLayout(LPCWSTR fullPath)

loadedImage = PAL_LOADLoadPEFile(fileHandle, 0);
}
ReportActionTime("LOAD_LIBRARY", fullPath, before);

#else
loadedImage = CLRLoadLibraryEx(fullPath, NULL, GetLoadWithAlteredSearchPathFlag());
#endif
Expand Down
82 changes: 82 additions & 0 deletions src/coreclr/vm/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -902,7 +902,77 @@ CLRUnmapViewOfFile(
}
}

volatile static int64_t s_totalTicks = 0;
volatile static LONG s_actionIndex = 0;

int64_t GetPreciseTickCount()
{
int64_t result;
QueryPerformanceCounter((LARGE_INTEGER *)&result);
return result;
}

void ReportActionTime(const char *actionName, LPCWSTR lpFileName, int64_t before)
{
int64_t duration = GetPreciseTickCount() - before;
long actionIndex = ::InterlockedAdd(&s_actionIndex, 1);
int64_t totalTime = ::InterlockedAdd64(&s_totalTicks, duration);
int64_t frequency;
QueryPerformanceFrequency((LARGE_INTEGER *)&frequency);
MAKE_UTF8PTR_FROMWIDE_NOTHROW(fileNameUtf8, lpFileName);
printf("\n[%ld]: %s '%s' - %.6f seconds, %.6f total\n",
actionIndex,
actionName,
fileNameUtf8,
duration / (double)frequency,
totalTime / (double)frequency);
}

void ReportPreloadTime(LPCWSTR lpFileName)
{
int64_t before = GetPreciseTickCount();

HANDLE handle = CreateFileW(
Copy link
Member

Choose a reason for hiding this comment

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

This may not be doing what you expect.

Windows uses separate caches for data files and PE binaries. PE binaries are cached in the "mapped" layout. I am not sure whether Windows is able to create the "mapped" layout from the raw data cache.

lpFileName,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);

if (handle == INVALID_HANDLE_VALUE)
{
MAKE_UTF8PTR_FROMWIDE_NOTHROW(fileNameUtf8, lpFileName);
printf("\nFile not found: '%s'\n", fileNameUtf8);
return;
}

DWORD high32;
DWORD low32 = GetFileSize(handle, &high32);
uint64_t reportedSize = low32 | ((uint64_t)high32 << 32);

const uint32_t chunkLimit = 1 << 24; // 16 M
uint32_t chunkSize = reportedSize < chunkLimit ? (uint32_t)reportedSize : chunkLimit;

void *buffer = malloc(chunkSize);
uint64_t loadedSize = 0;

for (DWORD numberOfBytesRead; ReadFile(handle, buffer, chunkSize, &numberOfBytesRead, NULL); loadedSize += numberOfBytesRead)
;

free(buffer);
CloseHandle(handle);

if (loadedSize != reportedSize)
{
MAKE_UTF8PTR_FROMWIDE_NOTHROW(fileNameUtf8, lpFileName);
printf("\nError reading file '%s' - reported size %llu, read size %llu\n", fileNameUtf8, reportedSize, loadedSize);
return;
}

ReportActionTime("PRELOAD", lpFileName, before);
}

static HMODULE CLRLoadLibraryWorker(LPCWSTR lpLibFileName, DWORD *pLastError)
{
Expand All @@ -914,9 +984,15 @@ static HMODULE CLRLoadLibraryWorker(LPCWSTR lpLibFileName, DWORD *pLastError)
HMODULE hMod;
ErrorModeHolder errorMode{};
{
ReportPreloadTime(lpLibFileName);

int64_t before = GetPreciseTickCount();

INDEBUG(PEDecoder::ForceRelocForDLL(lpLibFileName));
hMod = WszLoadLibrary(lpLibFileName);
*pLastError = GetLastError();

ReportActionTime("LOAD_LIBRARY", lpLibFileName, before);
}
return hMod;
}
Expand Down Expand Up @@ -950,9 +1026,15 @@ static HMODULE CLRLoadLibraryExWorker(LPCWSTR lpLibFileName, HANDLE hFile, DWORD
HMODULE hMod;
ErrorModeHolder errorMode{};
{
ReportPreloadTime(lpLibFileName);

int64_t before = GetPreciseTickCount();

INDEBUG(PEDecoder::ForceRelocForDLL(lpLibFileName));
hMod = WszLoadLibrary(lpLibFileName, hFile, dwFlags);
*pLastError = GetLastError();

ReportActionTime("LOAD_LIBRARY", lpLibFileName, before);
}
return hMod;
}
Expand Down
4 changes: 4 additions & 0 deletions src/coreclr/vm/util.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,10 @@ CLRUnmapViewOfFile(
IN LPVOID lpBaseAddress
);

int64_t GetPreciseTickCount();
void ReportActionTime(const char *actionName, LPCWSTR lpFileName, int64_t beforeTicks);
void ReportPreloadTime(LPCWSTR lpFileName);

#ifndef DACCESS_COMPILE
FORCEINLINE void VoidCLRUnmapViewOfFile(void *ptr) { CLRUnmapViewOfFile(ptr); }
typedef Wrapper<void *, DoNothing, VoidCLRUnmapViewOfFile> CLRMapViewHolder;
Expand Down