Skip to content

Commit

Permalink
Add background type preloading based on multicorejit (#52595)
Browse files Browse the repository at this point in the history
* Add background type preloading based on multicorejit

This is a second part of #48326 change, which enables handling of methods loaded from r2r images. Background thread of multicorejit now not only jits methods but also loads methods from R2R images. This allows to load types in background thread.

This is required as part of #45748 change (specifically, #45748 (comment)), goal of which is to enable background type preloading using multicorejit.
  • Loading branch information
gbalykov authored Jun 4, 2021
1 parent 39d2ba3 commit 951b424
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 50 deletions.
15 changes: 8 additions & 7 deletions src/coreclr/vm/method.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2023,7 +2023,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();
Expand Down Expand Up @@ -2208,7 +2208,8 @@ class PrepareCodeConfig
}
}

bool FinalizeOptimizationTierForTier0Jit();
bool FinalizeOptimizationTierForTier0Load();
bool FinalizeOptimizationTierForTier0LoadOrJit();
#endif

public:
Expand Down Expand Up @@ -2300,21 +2301,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;
Expand Down
8 changes: 4 additions & 4 deletions src/coreclr/vm/multicorejit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -869,7 +869,7 @@ void MulticoreJitRecorder::PreRecordFirstMethod()
}


void MulticoreJitRecorder::RecordMethodJit(MethodDesc * pMethod, bool application)
void MulticoreJitRecorder::RecordMethodJitOrLoad(MethodDesc * pMethod, bool application)
{
STANDARD_VM_CONTRACT;

Expand Down Expand Up @@ -1103,7 +1103,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
RecordMethodJitOrLoad(pMethod, false); // JITTed by background thread, returned to application
}

return codeInfo;
Expand Down Expand Up @@ -1426,15 +1426,15 @@ MulticoreJitCodeInfo MulticoreJitManager::RequestMethodCode(MethodDesc * pMethod
// Call back from MethodDesc::MakeJitWorker for
// Threading: protected by m_playerLock

void MulticoreJitManager::RecordMethodJit(MethodDesc * pMethod)
void MulticoreJitManager::RecordMethodJitOrLoad(MethodDesc * pMethod)
{
STANDARD_VM_CONTRACT;

CrstHolder hold(& m_playerLock);

if (m_pMulticoreJitRecorder != NULL)
{
m_pMulticoreJitRecorder->RecordMethodJit(pMethod, true);
m_pMulticoreJitRecorder->RecordMethodJitOrLoad(pMethod, true);

if (m_pMulticoreJitRecorder->IsAtFullCapacity())
{
Expand Down
10 changes: 5 additions & 5 deletions src/coreclr/vm/multicorejit.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,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;
Expand Down Expand Up @@ -118,12 +118,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
Expand Down Expand Up @@ -281,7 +281,7 @@ class MulticoreJitManager

MulticoreJitCodeInfo RequestMethodCode(MethodDesc * pMethod);

void RecordMethodJit(MethodDesc * pMethod);
void RecordMethodJitOrLoad(MethodDesc * pMethod);

MulticoreJitPlayerStat & GetStats()
{
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/vm/multicorejitimpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -705,7 +705,7 @@ class MulticoreJitRecorder
(m_ModuleCount >= MAX_MODULES);
}

void RecordMethodJit(MethodDesc * pMethod, bool application);
void RecordMethodJitOrLoad(MethodDesc * pMethod, bool application);

MulticoreJitCodeInfo RequestMethodCode(MethodDesc * pMethod, MulticoreJitManager * pManager);

Expand Down
14 changes: 7 additions & 7 deletions src/coreclr/vm/multicorejitplayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;

Expand All @@ -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())
Expand Down Expand Up @@ -890,7 +892,6 @@ HRESULT MulticoreJitProfilePlayer::HandleNonGenericMethodInfoRecord(unsigned mod
// Similar to Module::FindMethod + Module::FindMethodThrowing,
// except it calls GetMethodDescFromMemberDefOrRefOrSpec with strictMetadataChecks=FALSE to allow generic instantiation
MethodDesc * pMethod = MemberLoader::GetMethodDescFromMemberDefOrRefOrSpec(pModule, token, NULL, FALSE, FALSE);

CompileMethodInfoRecord(pModule, pMethod, false);
}
else
Expand Down Expand Up @@ -1292,7 +1293,6 @@ HRESULT MulticoreJitProfilePlayer::PlayProfile()
unsigned curdata1 = * (const unsigned *) pCurBuf;
unsigned currcdTyp = curdata1 >> RECORD_TYPE_OFFSET;
unsigned curmoduleIndex = curdata1 & MODULE_MASK;
unsigned curflags = curdata1 & METHOD_FLAGS_MASK;

if (currcdTyp == MULTICOREJIT_METHOD_RECORD_ID)
{
Expand Down
82 changes: 56 additions & 26 deletions src/coreclr/vm/prestub.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.RecordMethodJitOrLoad(this);
}
}
}
#endif
}
}
}
Expand Down Expand Up @@ -602,16 +627,17 @@ PCODE MethodDesc::GetPrecompiledR2RCode(PrepareCodeConfig* pConfig)
}
}
#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
Expand All @@ -625,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())
{
Expand Down Expand Up @@ -803,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))
Expand Down Expand Up @@ -1079,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
Expand Down Expand Up @@ -1126,7 +1152,7 @@ PCODE MethodDesc::JitCompileCodeLocked(PrepareCodeConfig* pConfig, JitListLockEn
{
if (MulticoreJitManager::IsMethodSupported(this))
{
mcJitManager.RecordMethodJit(this); // Tell multi-core JIT manager to record method on successful JITting
mcJitManager.RecordMethodJitOrLoad(this); // Tell multi-core JIT manager to record method on successful JITting
}
}
}
Expand Down Expand Up @@ -1325,18 +1351,35 @@ 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());

if (IsForMulticoreJit())
{
// 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
}

Expand Down Expand Up @@ -2229,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();
Expand Down

0 comments on commit 951b424

Please sign in to comment.