From 7debfe4b605a743b61eced52970563b59a4967ea Mon Sep 17 00:00:00 2001 From: =?utf8?q?Tom=C3=A1=C5=A1=20Rylek?= Date: Thu, 14 May 2020 22:19:08 +0200 Subject: [PATCH] Startup optimization w.r.t. manifest access in composite mode (#36446) During my work on fixing runtime crashes in composite build with large version bubble enabled I noticed room for startup perf improvement and a very slight working set optimization: For component assemblies of a composite image, we can basically share the cache of those manifest assembly references that have already been resolved (GetNativeMetadataAssemblyRefFromCache) within the native image because that is the logical owner of the manifest metadata. In the "asymptotic" case of composite images with many components, the pre-existing behavior was basically a quadratic O(n^2) algorithm in the number of component assemblies. This change reduces it to linear in the sense that all assembly references from the composite image get resolved only once. Thanks Tomas --- src/coreclr/src/vm/ceeload.cpp | 40 ++++++++++++++++++++++++++------------ src/coreclr/src/vm/ceeload.h | 11 ++++++----- src/coreclr/src/vm/nativeimage.cpp | 5 +++++ src/coreclr/src/vm/nativeimage.h | 2 ++ 4 files changed, 41 insertions(+), 17 deletions(-) diff --git a/src/coreclr/src/vm/ceeload.cpp b/src/coreclr/src/vm/ceeload.cpp index 30f6eee..acd979f 100644 --- a/src/coreclr/src/vm/ceeload.cpp +++ b/src/coreclr/src/vm/ceeload.cpp @@ -99,10 +99,10 @@ BOOL Module::HasNativeOrReadyToRunInlineTrackingMap() { LIMITED_METHOD_DAC_CONTRACT; #ifdef FEATURE_READYTORUN - if (IsReadyToRun() && GetReadyToRunInfo()->GetInlineTrackingMap() != NULL) - { - return TRUE; - } + if (IsReadyToRun() && GetReadyToRunInfo()->GetInlineTrackingMap() != NULL) + { + return TRUE; + } #endif return (m_pPersistentInlineTrackingMapNGen != NULL); } @@ -500,10 +500,9 @@ BOOL Module::IsPersistedObject(void *address) uint32_t Module::GetNativeMetadataAssemblyCount() { - NativeImage *compositeImage = GetCompositeNativeImage(); - if (compositeImage != NULL) + if (m_pNativeImage != NULL) { - return compositeImage->GetManifestAssemblyCount(); + return m_pNativeImage->GetManifestAssemblyCount(); } else { @@ -593,15 +592,25 @@ void Module::Initialize(AllocMemTracker *pamTracker, LPCWSTR szName) #endif // FEATURE_COLLECTIBLE_TYPES #ifdef FEATURE_READYTORUN + m_pNativeImage = NULL; if (!HasNativeImage() && !IsResource()) { if ((m_pReadyToRunInfo = ReadyToRunInfo::Initialize(this, pamTracker)) != NULL) { - COUNT_T cMeta = 0; - if (GetFile()->GetOpenedILimage()->GetNativeManifestMetadata(&cMeta) != NULL) + m_pNativeImage = m_pReadyToRunInfo->GetNativeImage(); + if (m_pNativeImage != NULL) + { + m_NativeMetadataAssemblyRefMap = m_pNativeImage->GetManifestMetadataAssemblyRefMap(); + } + else { - // Load the native assembly import - GetNativeAssemblyImport(TRUE /* loadAllowed */); + // For composite images, manifest metadata gets loaded as part of the native image + COUNT_T cMeta = 0; + if (GetFile()->GetOpenedILimage()->GetNativeManifestMetadata(&cMeta) != NULL) + { + // Load the native assembly import + GetNativeAssemblyImport(TRUE /* loadAllowed */); + } } } } @@ -9619,7 +9628,14 @@ void Module::Fixup(DataImage *image) image->ZeroField(this, offsetof(Module, m_AssemblyRefByNameCount), sizeof(m_AssemblyRefByNameCount)); image->ZeroPointerField(this, offsetof(Module, m_AssemblyRefByNameTable)); - image->ZeroPointerField(this,offsetof(Module, m_NativeMetadataAssemblyRefMap)); +#ifdef FEATURE_READYTORUN + // For composite ready-to-run images, the manifest assembly ref map is stored in the native image + // and shared by all its component images. + if (m_pNativeImage == NULL) +#endif + { + image->ZeroPointerField(this,offsetof(Module, m_NativeMetadataAssemblyRefMap)); + } // // Fixup statics diff --git a/src/coreclr/src/vm/ceeload.h b/src/coreclr/src/vm/ceeload.h index 9c11aa4..3619378 100644 --- a/src/coreclr/src/vm/ceeload.h +++ b/src/coreclr/src/vm/ceeload.h @@ -1615,6 +1615,7 @@ public: #ifdef FEATURE_READYTORUN private: PTR_ReadyToRunInfo m_pReadyToRunInfo; + PTR_NativeImage m_pNativeImage; #endif private: @@ -2924,17 +2925,17 @@ public: #endif } - NativeImage *GetCompositeNativeImage() const +#ifdef FEATURE_READYTORUN + PTR_ReadyToRunInfo GetReadyToRunInfo() const { LIMITED_METHOD_DAC_CONTRACT; - return (m_pReadyToRunInfo != NULL ? m_pReadyToRunInfo->GetNativeImage() : NULL); + return m_pReadyToRunInfo; } -#ifdef FEATURE_READYTORUN - PTR_ReadyToRunInfo GetReadyToRunInfo() const + PTR_NativeImage GetCompositeNativeImage() const { LIMITED_METHOD_DAC_CONTRACT; - return m_pReadyToRunInfo; + return m_pNativeImage; } #endif diff --git a/src/coreclr/src/vm/nativeimage.cpp b/src/coreclr/src/vm/nativeimage.cpp index 70ad31f..e181bfb 100644 --- a/src/coreclr/src/vm/nativeimage.cpp +++ b/src/coreclr/src/vm/nativeimage.cpp @@ -74,6 +74,11 @@ void NativeImage::Initialize(READYTORUN_HEADER *pHeader, LoaderAllocator *pLoade // count may exceed its component assembly count as it may contain references to // assemblies outside of the composite image that are part of its version bubble. _ASSERTE(m_manifestAssemblyCount >= m_componentAssemblyCount); + + S_SIZE_T dwAllocSize = S_SIZE_T(sizeof(PTR_Assembly)) * S_SIZE_T(m_manifestAssemblyCount); + + // Note: Memory allocated on loader heap is zero filled + m_pNativeMetadataAssemblyRefMap = (PTR_Assembly*)pamTracker->Track(pLoaderAllocator->GetLowFrequencyHeap()->AllocMem(dwAllocSize)); } NativeImage::~NativeImage() diff --git a/src/coreclr/src/vm/nativeimage.h b/src/coreclr/src/vm/nativeimage.h index 64cbf54..323a509 100644 --- a/src/coreclr/src/vm/nativeimage.h +++ b/src/coreclr/src/vm/nativeimage.h @@ -62,6 +62,7 @@ private: ReadyToRunInfo *m_pReadyToRunInfo; IMDInternalImport *m_pManifestMetadata; PEImageLayout *m_pImageLayout; + PTR_Assembly *m_pNativeMetadataAssemblyRefMap; IMAGE_DATA_DIRECTORY *m_pComponentAssemblies; uint32_t m_componentAssemblyCount; @@ -95,6 +96,7 @@ public: ReadyToRunInfo *GetReadyToRunInfo() const { return m_pReadyToRunInfo; } IMDInternalImport *GetManifestMetadata() const { return m_pManifestMetadata; } uint32_t GetManifestAssemblyCount() const { return m_manifestAssemblyCount; } + PTR_Assembly *GetManifestMetadataAssemblyRefMap() { return m_pNativeMetadataAssemblyRefMap; } Assembly *LoadManifestAssembly(uint32_t rowid); -- 2.7.4