From e0d3216109241e6863aeedbc333edd0a9c4ffa8a Mon Sep 17 00:00:00 2001 From: Gleb Balykov Date: Wed, 5 May 2021 11:42:27 +0300 Subject: [PATCH 1/2] Add background type preloading based on multicorejit --- src/coreclr/vm/multicorejit.cpp | 30 ++++++++++++++++++++----- src/coreclr/vm/multicorejit.h | 2 ++ src/coreclr/vm/multicorejitimpl.h | 20 +++++++++++------ src/coreclr/vm/multicorejitplayer.cpp | 32 ++++++++++++++++++++------- src/coreclr/vm/prestub.cpp | 18 +++++++++++++++ 5 files changed, 81 insertions(+), 21 deletions(-) diff --git a/src/coreclr/vm/multicorejit.cpp b/src/coreclr/vm/multicorejit.cpp index 9a9ec83684080f..545b0b832fcac8 100644 --- a/src/coreclr/vm/multicorejit.cpp +++ b/src/coreclr/vm/multicorejit.cpp @@ -471,6 +471,7 @@ HRESULT MulticoreJitRecorder::WriteOutput(IStream * pStream) header.shortCounters[ 8] = m_stats.m_nDelayCount; header.shortCounters[ 9] = m_stats.m_nWalkBack; header.shortCounters[10] = m_fAppxMode; + header.shortCounters[11] = m_stats.m_nNoJitCount; _ASSERTE(HEADER_W_COUNTER >= 14); @@ -600,14 +601,14 @@ unsigned MulticoreJitRecorder::GetOrAddModuleIndex(Module * pModule) return slot; } -void MulticoreJitRecorder::RecordMethodInfo(unsigned moduleIndex, MethodDesc * pMethod, bool application) +void MulticoreJitRecorder::RecordMethodInfo(unsigned moduleIndex, MethodDesc * pMethod, bool application, bool dojit) { LIMITED_METHOD_CONTRACT; if (m_JitInfoArray != nullptr && m_JitInfoCount < (LONG) MAX_METHODS) { m_ModuleList[moduleIndex].methodCount++; - m_JitInfoArray[m_JitInfoCount++].PackMethod(moduleIndex, pMethod, application); + m_JitInfoArray[m_JitInfoCount++].PackMethod(moduleIndex, pMethod, application, dojit); } } @@ -869,7 +870,7 @@ void MulticoreJitRecorder::PreRecordFirstMethod() } -void MulticoreJitRecorder::RecordMethodJit(MethodDesc * pMethod, bool application) +void MulticoreJitRecorder::RecordMethodJit(MethodDesc * pMethod, bool application, bool dojit) { STANDARD_VM_CONTRACT; @@ -888,7 +889,7 @@ void MulticoreJitRecorder::RecordMethodJit(MethodDesc * pMethod, bool applicatio return; } - RecordMethodInfo(moduleIndex, pMethod, application); + RecordMethodInfo(moduleIndex, pMethod, application, dojit); } @@ -1103,7 +1104,7 @@ MulticoreJitCodeInfo MulticoreJitRecorder::RequestMethodCode(MethodDesc * pMetho if (!codeInfo.IsNull() && pManager->IsRecorderActive()) // recorder may be off when player is on (e.g. for Appx) { - RecordMethodJit(pMethod, false); // JITTed by background thread, returned to application + RecordMethodJit(pMethod, false, true); // JITTed by background thread, returned to application } return codeInfo; @@ -1434,7 +1435,24 @@ void MulticoreJitManager::RecordMethodJit(MethodDesc * pMethod) if (m_pMulticoreJitRecorder != NULL) { - m_pMulticoreJitRecorder->RecordMethodJit(pMethod, true); + m_pMulticoreJitRecorder->RecordMethodJit(pMethod, true, true); + + if (m_pMulticoreJitRecorder->IsAtFullCapacity()) + { + m_fRecorderActive = false; + } + } +} + +void MulticoreJitManager::RecordMethodLoad(MethodDesc * pMethod) +{ + STANDARD_VM_CONTRACT; + + CrstHolder hold(& m_playerLock); + + if (m_pMulticoreJitRecorder != NULL) + { + m_pMulticoreJitRecorder->RecordMethodJit(pMethod, true, false); if (m_pMulticoreJitRecorder->IsAtFullCapacity()) { diff --git a/src/coreclr/vm/multicorejit.h b/src/coreclr/vm/multicorejit.h index 4e199a4ae0fb52..537292e6dc0bfc 100644 --- a/src/coreclr/vm/multicorejit.h +++ b/src/coreclr/vm/multicorejit.h @@ -62,6 +62,7 @@ struct MulticoreJitPlayerStat unsigned short m_nTotalDelay; unsigned short m_nDelayCount; unsigned short m_nWalkBack; + unsigned short m_nNoJitCount; HRESULT m_hr; @@ -282,6 +283,7 @@ class MulticoreJitManager MulticoreJitCodeInfo RequestMethodCode(MethodDesc * pMethod); void RecordMethodJit(MethodDesc * pMethod); + void RecordMethodLoad(MethodDesc * pMethod); MulticoreJitPlayerStat & GetStats() { diff --git a/src/coreclr/vm/multicorejitimpl.h b/src/coreclr/vm/multicorejitimpl.h index 35ea8a3dc8a269..41445016732f34 100644 --- a/src/coreclr/vm/multicorejitimpl.h +++ b/src/coreclr/vm/multicorejitimpl.h @@ -23,7 +23,8 @@ // Bits 0xff0000 are reserved method flags. Currently only first bit is used. const unsigned METHOD_FLAGS_MASK = 0xff0000; const unsigned JIT_BY_APP_THREAD_TAG = 0x10000; // tag, that indicates whether method is jitted by application thread(1) or background thread(0) -// Tags 0xfe0000 are currently free +const unsigned NO_JIT_TAG = 0x20000; // tag, that indicates whether method should be jitted or simply loaded (i.e. related types are created, etc.) +// Tags 0xfc0000 are currently free const unsigned RECORD_TYPE_OFFSET = 24; // offset of type of record @@ -45,7 +46,7 @@ const int MAX_WALKBACK = 128; enum { - MULTICOREJIT_PROFILE_VERSION = 102, + MULTICOREJIT_PROFILE_VERSION = 103, MULTICOREJIT_HEADER_RECORD_ID = 1, MULTICOREJIT_MODULE_RECORD_ID = 2, @@ -297,8 +298,8 @@ friend class MulticoreJitRecorder; HRESULT HandleModuleRecord(const ModuleRecord * pMod); HRESULT HandleModuleInfoRecord(unsigned moduleTo, unsigned level); - HRESULT HandleNonGenericMethodInfoRecord(unsigned moduleIndex, unsigned token); - HRESULT HandleGenericMethodInfoRecord(unsigned moduleIndex, BYTE * signature, unsigned length); + HRESULT HandleNonGenericMethodInfoRecord(unsigned moduleIndex, unsigned token, bool dojit); + HRESULT HandleGenericMethodInfoRecord(unsigned moduleIndex, BYTE * signature, unsigned length, bool dojit); void CompileMethodInfoRecord(Module *pModule, MethodDesc *pMethod, bool isGeneric); bool CompileMethodDesc(Module * pModule, MethodDesc * pMD); @@ -559,7 +560,7 @@ struct RecorderInfo _ASSERTE(IsFullyInitialized()); } - void PackMethod(unsigned moduleIndex, MethodDesc * pMethod, bool application) + void PackMethod(unsigned moduleIndex, MethodDesc * pMethod, bool application, bool dojit) { LIMITED_METHOD_CONTRACT; @@ -586,6 +587,11 @@ struct RecorderInfo data1 |= JIT_BY_APP_THREAD_TAG; } + if (!dojit) + { + data1 |= NO_JIT_TAG; + } + data2 = 0; // To avoid recording overhead, records only pointer to MethodDesc. ptr = (BYTE *) pMethod; @@ -639,7 +645,7 @@ class MulticoreJitRecorder HRESULT WriteModuleRecord(IStream * pStream, const RecorderModuleInfo & module); - void RecordMethodInfo(unsigned moduleIndex, MethodDesc * pMethod, bool application); + void RecordMethodInfo(unsigned moduleIndex, MethodDesc * pMethod, bool application, bool dojit); unsigned RecordModuleInfo(Module * pModule); void RecordOrUpdateModuleInfo(FileLoadLevel needLevel, unsigned moduleIndex); @@ -710,7 +716,7 @@ class MulticoreJitRecorder (m_ModuleCount >= MAX_MODULES); } - void RecordMethodJit(MethodDesc * pMethod, bool application); + void RecordMethodJit(MethodDesc * pMethod, bool application, bool dojit); MulticoreJitCodeInfo RequestMethodCode(MethodDesc * pMethod, MulticoreJitManager * pManager); diff --git a/src/coreclr/vm/multicorejitplayer.cpp b/src/coreclr/vm/multicorejitplayer.cpp index ab243cc89a3c5c..cea28e4a6e5f83 100644 --- a/src/coreclr/vm/multicorejitplayer.cpp +++ b/src/coreclr/vm/multicorejitplayer.cpp @@ -865,7 +865,7 @@ DomainAssembly * MulticoreJitProfilePlayer::LoadAssembly(SString & assemblyName) FALSE); // Don't throw on FileNotFound. } -HRESULT MulticoreJitProfilePlayer::HandleNonGenericMethodInfoRecord(unsigned moduleIndex, unsigned token) +HRESULT MulticoreJitProfilePlayer::HandleNonGenericMethodInfoRecord(unsigned moduleIndex, unsigned token, bool dojit) { STANDARD_VM_CONTRACT; @@ -891,7 +891,14 @@ HRESULT MulticoreJitProfilePlayer::HandleNonGenericMethodInfoRecord(unsigned mod // except it calls GetMethodDescFromMemberDefOrRefOrSpec with strictMetadataChecks=FALSE to allow generic instantiation MethodDesc * pMethod = MemberLoader::GetMethodDescFromMemberDefOrRefOrSpec(pModule, token, NULL, FALSE, FALSE); - CompileMethodInfoRecord(pModule, pMethod, false); + if (dojit) + { + CompileMethodInfoRecord(pModule, pMethod, false); + } + else + { + m_stats.m_nNoJitCount++; + } } else { @@ -911,7 +918,7 @@ HRESULT MulticoreJitProfilePlayer::HandleNonGenericMethodInfoRecord(unsigned mod return hr; } -HRESULT MulticoreJitProfilePlayer::HandleGenericMethodInfoRecord(unsigned moduleIndex, BYTE * signature, unsigned length) +HRESULT MulticoreJitProfilePlayer::HandleGenericMethodInfoRecord(unsigned moduleIndex, BYTE * signature, unsigned length, bool dojit) { STANDARD_VM_CONTRACT; @@ -945,7 +952,14 @@ HRESULT MulticoreJitProfilePlayer::HandleGenericMethodInfoRecord(unsigned module } EX_END_CATCH(SwallowAllExceptions); - CompileMethodInfoRecord(pModule, pMethod, true); + if (dojit) + { + CompileMethodInfoRecord(pModule, pMethod, true); + } + else + { + m_stats.m_nNoJitCount++; + } } else { @@ -1017,8 +1031,9 @@ void MulticoreJitProfilePlayer::TraceSummary() unsigned compiled = curStorage.GetStored(); - MulticoreJitTrace(("PlayerSummary: %d total: %d no mod, %d filtered out, %d had code, %d other, %d tried, %d compiled, %d returned, %d%% efficiency, %d mod loaded, %d ms delay(%d)", + MulticoreJitTrace(("PlayerSummary: %d total, %d no jit: %d no mod, %d filtered out, %d had code, %d other, %d tried, %d compiled, %d returned, %d%% efficiency, %d mod loaded, %d ms delay(%d)", m_stats.m_nTotalMethod, + m_stats.m_nNoJitCount, m_stats.m_nMissingModuleSkip, m_stats.m_nFilteredMethods, m_stats.m_nHasNativeCode, @@ -1026,7 +1041,7 @@ void MulticoreJitProfilePlayer::TraceSummary() m_stats.m_nTryCompiling, compiled, returned, - (m_stats.m_nTotalMethod == 0) ? 100 : returned * 100 / m_stats.m_nTotalMethod, + (m_stats.m_nTotalMethod == 0) ? 100 : returned * 100 / (m_stats.m_nTotalMethod - m_stats.m_nNoJitCount), m_nLoadedModuleCount, m_stats.m_nTotalDelay, m_stats.m_nDelayCount @@ -1293,12 +1308,13 @@ HRESULT MulticoreJitProfilePlayer::PlayProfile() unsigned currcdTyp = curdata1 >> RECORD_TYPE_OFFSET; unsigned curmoduleIndex = curdata1 & MODULE_MASK; unsigned curflags = curdata1 & METHOD_FLAGS_MASK; + bool dojit = (curflags & NO_JIT_TAG) == 0; if (currcdTyp == MULTICOREJIT_METHOD_RECORD_ID) { unsigned token = * (((const unsigned *) pCurBuf) + 1); - hr = HandleNonGenericMethodInfoRecord(curmoduleIndex, token); + hr = HandleNonGenericMethodInfoRecord(curmoduleIndex, token, dojit); } else { @@ -1306,7 +1322,7 @@ HRESULT MulticoreJitProfilePlayer::PlayProfile() unsigned cursignatureLength = * (const unsigned short *) (((const unsigned *) pCurBuf) + 1); - hr = HandleGenericMethodInfoRecord(curmoduleIndex, (BYTE *) (pCurBuf + sizeof(unsigned) + sizeof(unsigned short)), cursignatureLength); + hr = HandleGenericMethodInfoRecord(curmoduleIndex, (BYTE *) (pCurBuf + sizeof(unsigned) + sizeof(unsigned short)), cursignatureLength, dojit); } if (SUCCEEDED(hr) && ShouldAbort(false)) diff --git a/src/coreclr/vm/prestub.cpp b/src/coreclr/vm/prestub.cpp index 01fa3287d3f702..e9f0109fa22d02 100644 --- a/src/coreclr/vm/prestub.cpp +++ b/src/coreclr/vm/prestub.cpp @@ -602,6 +602,24 @@ PCODE MethodDesc::GetPrecompiledR2RCode(PrepareCodeConfig* pConfig) } } #endif + +#ifdef FEATURE_MULTICOREJIT + if (pCode != NULL && pConfig->NeedsMulticoreJitNotification()) + { + _ASSERTE(pConfig->GetCodeVersion().IsDefaultVersion()); + _ASSERTE(!pConfig->IsForMulticoreJit()); + + MulticoreJitManager & mcJitManager = GetAppDomain()->GetMulticoreJitManager(); + if (mcJitManager.IsRecorderActive()) + { + if (MulticoreJitManager::IsMethodSupported(this)) + { + mcJitManager.RecordMethodLoad(this); // Tell multi-core JIT manager to record method on successful load from R2R + } + } + } +#endif + return pCode; } From d7e9cea0170dba0ab09c03200c406250bbfb820f Mon Sep 17 00:00:00 2001 From: Koundinya Veluri Date: Mon, 24 May 2021 13:49:49 -0700 Subject: [PATCH 2/2] Fixed a few issues/assumptions relevant to MCJ recording and playing back R2R'ed code - Renamed `*wasTier0Jit` to `wasTier0` to include pregenerated code that is loaded, which is considered tier 0 - Added a subset of `FinalizeOptimizationTierForTier0Jit` as `FinalizeOptimizationTierForTier0Load` to set the `wasTier0` flag so that those methods would be call-counted for tiering when MCJ-loaded code is used, and updated the relevant code - Moved recording of loaded method code to after a successful `SetNativeCode()` to prevent duplicate recordings of the same method in multi-threaded races - Enabled `MulticoreJitPrepareCodeConfig` to look up pregenerated code to parallelize that work --- src/coreclr/vm/method.hpp | 15 +++-- src/coreclr/vm/multicorejit.h | 8 +-- src/coreclr/vm/multicorejitplayer.cpp | 12 ++-- src/coreclr/vm/prestub.cpp | 96 +++++++++++++++------------ 4 files changed, 73 insertions(+), 58 deletions(-) diff --git a/src/coreclr/vm/method.hpp b/src/coreclr/vm/method.hpp index b536101c5dd91a..266b3f0cf38d91 100644 --- a/src/coreclr/vm/method.hpp +++ b/src/coreclr/vm/method.hpp @@ -2022,7 +2022,7 @@ class MethodDesc PCODE GetPrecompiledCode(PrepareCodeConfig* pConfig, bool shouldTier); PCODE GetPrecompiledNgenCode(PrepareCodeConfig* pConfig); PCODE GetPrecompiledR2RCode(PrepareCodeConfig* pConfig); - PCODE GetMulticoreJitCode(PrepareCodeConfig* pConfig, bool* pWasTier0Jit); + PCODE GetMulticoreJitCode(PrepareCodeConfig* pConfig, bool* pWasTier0); COR_ILMETHOD_DECODER* GetAndVerifyILHeader(PrepareCodeConfig* pConfig, COR_ILMETHOD_DECODER* pIlDecoderMemory); COR_ILMETHOD_DECODER* GetAndVerifyMetadataILHeader(PrepareCodeConfig* pConfig, COR_ILMETHOD_DECODER* pIlDecoderMemory); COR_ILMETHOD_DECODER* GetAndVerifyNoMetadataILHeader(); @@ -2207,7 +2207,8 @@ class PrepareCodeConfig } } - bool FinalizeOptimizationTierForTier0Jit(); + bool FinalizeOptimizationTierForTier0Load(); + bool FinalizeOptimizationTierForTier0LoadOrJit(); #endif public: @@ -2299,21 +2300,21 @@ class PrepareCodeConfigBuffer class MulticoreJitPrepareCodeConfig : public PrepareCodeConfig { private: - bool m_wasTier0Jit; + bool m_wasTier0; public: MulticoreJitPrepareCodeConfig(MethodDesc* pMethod); - bool WasTier0Jit() const + bool WasTier0() const { LIMITED_METHOD_CONTRACT; - return m_wasTier0Jit; + return m_wasTier0; } - void SetWasTier0Jit() + void SetWasTier0() { LIMITED_METHOD_CONTRACT; - m_wasTier0Jit = true; + m_wasTier0 = true; } virtual BOOL SetNativeCode(PCODE pCode, PCODE * ppAlternateCodeToUse) override; diff --git a/src/coreclr/vm/multicorejit.h b/src/coreclr/vm/multicorejit.h index 537292e6dc0bfc..e35a7a4cd7e816 100644 --- a/src/coreclr/vm/multicorejit.h +++ b/src/coreclr/vm/multicorejit.h @@ -85,9 +85,9 @@ class MulticoreJitCodeInfo enum class TierInfo : TADDR { None = 0, - WasTier0Jit = 1 << 0, + WasTier0 = 1 << 0, JitSwitchedToOptimized = 1 << 1, - Mask = None | WasTier0Jit | JitSwitchedToOptimized + Mask = None | WasTier0 | JitSwitchedToOptimized }; TADDR m_entryPointAndTierInfo; @@ -119,12 +119,12 @@ class MulticoreJitCodeInfo return IsNull() ? NULL : PINSTRToPCODE(m_entryPointAndTierInfo & ~(TADDR)TierInfo::Mask); } - bool WasTier0Jit() const + bool WasTier0() const { WRAPPER_NO_CONTRACT; VerifyIsNotNull(); - return (m_entryPointAndTierInfo & (TADDR)TierInfo::WasTier0Jit) != 0; + return (m_entryPointAndTierInfo & (TADDR)TierInfo::WasTier0) != 0; } bool JitSwitchedToOptimized() const diff --git a/src/coreclr/vm/multicorejitplayer.cpp b/src/coreclr/vm/multicorejitplayer.cpp index cea28e4a6e5f83..ef442b5520cbe2 100644 --- a/src/coreclr/vm/multicorejitplayer.cpp +++ b/src/coreclr/vm/multicorejitplayer.cpp @@ -87,7 +87,7 @@ void MulticoreJitCodeStorage::StoreMethodCode(MethodDesc * pMD, MulticoreJitCode "%p %p %d %d StoredMethodCode", pMD, codeInfo.GetEntryPoint(), - (int)codeInfo.WasTier0Jit(), + (int)codeInfo.WasTier0(), (int)codeInfo.JitSwitchedToOptimized())); } #endif @@ -131,7 +131,7 @@ MulticoreJitCodeInfo MulticoreJitCodeStorage::QueryAndRemoveMethodCode(MethodDes "%p %p %d %d QueryAndRemoveMethodCode", pMethod, codeInfo.GetEntryPoint(), - (int)codeInfo.WasTier0Jit(), + (int)codeInfo.WasTier0(), (int)codeInfo.JitSwitchedToOptimized())); } #endif @@ -521,7 +521,9 @@ HRESULT MulticoreJitProfilePlayer::HandleModuleRecord(const ModuleRecord * pMod) #ifndef DACCESS_COMPILE MulticoreJitPrepareCodeConfig::MulticoreJitPrepareCodeConfig(MethodDesc* pMethod) : - PrepareCodeConfig(NativeCodeVersion(pMethod), FALSE, FALSE), m_wasTier0Jit(false) + // Method code that was pregenerated and loaded is recorded in the multi-core JIT profile, so enable multi-core JIT to also + // look up pregenerated code to help parallelize the work + PrepareCodeConfig(NativeCodeVersion(pMethod), FALSE, TRUE), m_wasTier0(false) { WRAPPER_NO_CONTRACT; @@ -548,9 +550,9 @@ MulticoreJitCodeInfo::MulticoreJitCodeInfo(PCODE entryPoint, const MulticoreJitP _ASSERTE((m_entryPointAndTierInfo & (TADDR)TierInfo::Mask) == 0); #ifdef FEATURE_TIERED_COMPILATION - if (pConfig->WasTier0Jit()) + if (pConfig->WasTier0()) { - m_entryPointAndTierInfo |= (TADDR)TierInfo::WasTier0Jit; + m_entryPointAndTierInfo |= (TADDR)TierInfo::WasTier0; } if (pConfig->JitSwitchedToOptimized()) diff --git a/src/coreclr/vm/prestub.cpp b/src/coreclr/vm/prestub.cpp index e9f0109fa22d02..beb47fd59efcdf 100644 --- a/src/coreclr/vm/prestub.cpp +++ b/src/coreclr/vm/prestub.cpp @@ -470,18 +470,43 @@ PCODE MethodDesc::GetPrecompiledCode(PrepareCodeConfig* pConfig, bool shouldTier { LOG_USING_R2R_CODE(this); +#ifdef FEATURE_TIERED_COMPILATION + // Finalize the optimization tier before SetNativeCode() is called + bool shouldCountCalls = shouldTier && pConfig->FinalizeOptimizationTierForTier0Load(); +#endif + if (pConfig->SetNativeCode(pCode, &pCode)) { #ifdef FEATURE_CODE_VERSIONING pConfig->SetGeneratedOrLoadedNewCode(); #endif #ifdef FEATURE_TIERED_COMPILATION - if (shouldTier) + if (shouldCountCalls) { _ASSERTE(pConfig->GetCodeVersion().GetOptimizationTier() == NativeCodeVersion::OptimizationTier0); pConfig->SetShouldCountCalls(); } #endif + +#ifdef FEATURE_MULTICOREJIT + // Multi-core JIT is only applicable to the default code version. A method is recorded in the profile only when + // SetNativeCode() above succeeds to avoid recording duplicates in the multi-core JIT profile. Successful loads + // of R2R code are also recorded. + if (pConfig->NeedsMulticoreJitNotification()) + { + _ASSERTE(pConfig->GetCodeVersion().IsDefaultVersion()); + _ASSERTE(!pConfig->IsForMulticoreJit()); + + MulticoreJitManager & mcJitManager = GetAppDomain()->GetMulticoreJitManager(); + if (mcJitManager.IsRecorderActive()) + { + if (MulticoreJitManager::IsMethodSupported(this)) + { + mcJitManager.RecordMethodLoad(this); + } + } + } +#endif } } } @@ -603,33 +628,16 @@ PCODE MethodDesc::GetPrecompiledR2RCode(PrepareCodeConfig* pConfig) } #endif -#ifdef FEATURE_MULTICOREJIT - if (pCode != NULL && pConfig->NeedsMulticoreJitNotification()) - { - _ASSERTE(pConfig->GetCodeVersion().IsDefaultVersion()); - _ASSERTE(!pConfig->IsForMulticoreJit()); - - MulticoreJitManager & mcJitManager = GetAppDomain()->GetMulticoreJitManager(); - if (mcJitManager.IsRecorderActive()) - { - if (MulticoreJitManager::IsMethodSupported(this)) - { - mcJitManager.RecordMethodLoad(this); // Tell multi-core JIT manager to record method on successful load from R2R - } - } - } -#endif - return pCode; } -PCODE MethodDesc::GetMulticoreJitCode(PrepareCodeConfig* pConfig, bool* pWasTier0Jit) +PCODE MethodDesc::GetMulticoreJitCode(PrepareCodeConfig* pConfig, bool* pWasTier0) { STANDARD_VM_CONTRACT; _ASSERTE(pConfig != NULL); _ASSERTE(pConfig->GetMethodDesc() == this); - _ASSERTE(pWasTier0Jit != NULL); - _ASSERTE(!*pWasTier0Jit); + _ASSERTE(pWasTier0 != NULL); + _ASSERTE(!*pWasTier0); MulticoreJitCodeInfo codeInfo; #ifdef FEATURE_MULTICOREJIT @@ -643,9 +651,9 @@ PCODE MethodDesc::GetMulticoreJitCode(PrepareCodeConfig* pConfig, bool* pWasTier #ifdef FEATURE_TIERED_COMPILATION if (!codeInfo.IsNull()) { - if (codeInfo.WasTier0Jit()) + if (codeInfo.WasTier0()) { - *pWasTier0Jit = true; + *pWasTier0 = true; } if (codeInfo.JitSwitchedToOptimized()) { @@ -821,13 +829,13 @@ PCODE MethodDesc::JitCompileCode(PrepareCodeConfig* pConfig) NativeCodeVersion codeVersion = pConfig->GetCodeVersion(); if (codeVersion.IsDefaultVersion()) { - bool wasTier0Jit = false; - pCode = GetMulticoreJitCode(pConfig, &wasTier0Jit); + bool wasTier0 = false; + pCode = GetMulticoreJitCode(pConfig, &wasTier0); if (pCode != NULL) { #ifdef FEATURE_TIERED_COMPILATION // Finalize the optimization tier before SetNativeCode() is called - bool shouldCountCalls = wasTier0Jit && pConfig->FinalizeOptimizationTierForTier0Jit(); + bool shouldCountCalls = wasTier0 && pConfig->FinalizeOptimizationTierForTier0LoadOrJit(); #endif if (pConfig->SetNativeCode(pCode, &pCode)) @@ -1097,7 +1105,7 @@ PCODE MethodDesc::JitCompileCodeLocked(PrepareCodeConfig* pConfig, JitListLockEn #ifdef FEATURE_TIERED_COMPILATION // Finalize the optimization tier before SetNativeCode() is called - bool shouldCountCalls = pFlags->IsSet(CORJIT_FLAGS::CORJIT_FLAG_TIER0) && pConfig->FinalizeOptimizationTierForTier0Jit(); + bool shouldCountCalls = pFlags->IsSet(CORJIT_FLAGS::CORJIT_FLAG_TIER0) && pConfig->FinalizeOptimizationTierForTier0LoadOrJit(); #endif // Aside from rejit, performing a SetNativeCodeInterlocked at this point @@ -1343,10 +1351,27 @@ const char *PrepareCodeConfig::GetJitOptimizationTierStr(PrepareCodeConfig *conf } #ifdef FEATURE_TIERED_COMPILATION +// This function should be called before SetNativeCode() for consistency with usage of FinalizeOptimizationTierForTier0Jit +bool PrepareCodeConfig::FinalizeOptimizationTierForTier0Load() +{ + _ASSERTE(GetMethodDesc()->IsEligibleForTieredCompilation()); + _ASSERTE(!JitSwitchedToOptimized()); + + if (!IsForMulticoreJit()) + { + return true; // should count calls if SetNativeCode() succeeds + } + + // When using multi-core JIT, the loaded code would not be used until the method is called. Record some information that may + // be used later when the method is called. + ((MulticoreJitPrepareCodeConfig *)this)->SetWasTier0(); + return false; // don't count calls +} + // This function should be called before SetNativeCode() to update the optimization tier if necessary before SetNativeCode() is // called. As soon as SetNativeCode() is called, another thread may get the native code and the optimization tier for that code // version, and it should have already been finalized. -bool PrepareCodeConfig::FinalizeOptimizationTierForTier0Jit() +bool PrepareCodeConfig::FinalizeOptimizationTierForTier0LoadOrJit() { _ASSERTE(GetMethodDesc()->IsEligibleForTieredCompilation()); @@ -1354,7 +1379,7 @@ bool PrepareCodeConfig::FinalizeOptimizationTierForTier0Jit() { // When using multi-core JIT, the jitted code would not be used until the method is called. Don't make changes to the // optimization tier yet, just record some information that may be used later when the method is called. - ((MulticoreJitPrepareCodeConfig *)this)->SetWasTier0Jit(); + ((MulticoreJitPrepareCodeConfig *)this)->SetWasTier0(); return false; // don't count calls } @@ -2247,19 +2272,6 @@ PCODE MethodDesc::DoPrestub(MethodTable *pDispatchingMT, CallerGCMode callerGCMo if (pCode == NULL) { pCode = GetStubForInteropMethod(this); -#ifdef FEATURE_MULTICOREJIT - if (pCode) - { - MulticoreJitManager & mcJitManager = GetAppDomain()->GetMulticoreJitManager(); - if (mcJitManager.IsRecorderActive()) - { - if (MulticoreJitManager::IsMethodSupported(this)) - { - mcJitManager.RecordMethodJit(this); // Tell multi-core JIT manager to record method on successful JITting - } - } - } -#endif // FEATURE_MULTICOREJIT } GetOrCreatePrecode();