Skip to content

Commit

Permalink
Add profile-use-only mode for MultiCoreJit (#55005)
Browse files Browse the repository at this point in the history
* Add profile-use-only mode for MultiCoreJit

- memory consumption is reduced if profile is not gathered
- disk/flash life is increased if profile is not saved each time

* Remove non-set m_fAppxMode
  • Loading branch information
gbalykov authored Jul 20, 2021
1 parent b29d06c commit cbfa7cf
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 54 deletions.
1 change: 1 addition & 0 deletions src/coreclr/inc/clrconfigvalues.h
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,7 @@ RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_TrackDynamicMethodDebugInfo, W("TrackDynami
RETAIL_CONFIG_STRING_INFO(INTERNAL_MultiCoreJitProfile, W("MultiCoreJitProfile"), "If set, use the file to store/control multi-core JIT.")
RETAIL_CONFIG_DWORD_INFO(INTERNAL_MultiCoreJitProfileWriteDelay, W("MultiCoreJitProfileWriteDelay"), 12, "Set the delay after which the multi-core JIT profile will be written to disk.")
RETAIL_CONFIG_DWORD_INFO(INTERNAL_MultiCoreJitMinNumCpus, W("MultiCoreJitMinNumCpus"), 2, "Minimum number of cpus that must be present to allow MultiCoreJit usage.")
RETAIL_CONFIG_DWORD_INFO(INTERNAL_MultiCoreJitNoProfileGather, W("MultiCoreJitNoProfileGather"), 0, "Set to 1 to disable profile gathering (but leave possibly enabled profile usage).")

#endif

Expand Down
63 changes: 38 additions & 25 deletions src/coreclr/vm/multicorejit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,11 @@ HRESULT MulticoreJitRecorder::WriteOutput()

HRESULT hr = E_FAIL;

if (m_JitInfoArray == nullptr || m_ModuleList == nullptr)
{
return S_OK;
}

// Go into preemptive mode for file operations
GCX_PREEMP();

Expand Down Expand Up @@ -386,6 +391,9 @@ HRESULT MulticoreJitRecorder::WriteOutput(IStream * pStream)

HRESULT hr = S_OK;

_ASSERTE(m_JitInfoArray != nullptr);
_ASSERTE(m_ModuleList != nullptr);

// Preprocessing Methods
LONG skipped = 0;

Expand Down Expand Up @@ -470,7 +478,6 @@ HRESULT MulticoreJitRecorder::WriteOutput(IStream * pStream)
header.shortCounters[ 7] = m_stats.m_nTotalDelay;
header.shortCounters[ 8] = m_stats.m_nDelayCount;
header.shortCounters[ 9] = m_stats.m_nWalkBack;
header.shortCounters[10] = m_fAppxMode;

_ASSERTE(HEADER_W_COUNTER >= 14);

Expand Down Expand Up @@ -567,6 +574,8 @@ unsigned MulticoreJitRecorder::FindModule(Module * pModule)
{
LIMITED_METHOD_CONTRACT;

_ASSERTE(m_ModuleList != nullptr);

for (unsigned i = 0 ; i < m_ModuleCount; i ++)
{
if (m_ModuleList[i].pModule == pModule)
Expand All @@ -585,6 +594,8 @@ unsigned MulticoreJitRecorder::GetOrAddModuleIndex(Module * pModule)
{
STANDARD_VM_CONTRACT;

_ASSERTE(m_ModuleList != nullptr);

unsigned slot = FindModule(pModule);

if ((slot == UINT_MAX) && (m_ModuleCount < MAX_MODULES))
Expand All @@ -604,7 +615,10 @@ void MulticoreJitRecorder::RecordMethodInfo(unsigned moduleIndex, MethodDesc * p
{
LIMITED_METHOD_CONTRACT;

if (m_JitInfoArray != nullptr && m_JitInfoCount < (LONG) MAX_METHODS)
_ASSERTE(m_JitInfoArray != nullptr);
_ASSERTE(m_ModuleList != nullptr);

if (m_JitInfoCount < (LONG) MAX_METHODS)
{
m_ModuleList[moduleIndex].methodCount++;
m_JitInfoArray[m_JitInfoCount++].PackMethod(moduleIndex, pMethod, application);
Expand All @@ -615,6 +629,8 @@ unsigned MulticoreJitRecorder::RecordModuleInfo(Module * pModule)
{
LIMITED_METHOD_CONTRACT;

_ASSERTE(m_ModuleList != nullptr);

// pModule could be unknown at this point (modules not enumerated, no event received yet)
unsigned moduleIndex = GetOrAddModuleIndex(pModule);

Expand Down Expand Up @@ -675,7 +691,6 @@ void MulticoreJitRecorder::RecordOrUpdateModuleInfo(FileLoadLevel needLevel, uns
class MulticoreJitRecorderModuleEnumerator : public MulticoreJitModuleEnumerator
{
MulticoreJitRecorder * m_pRecorder;
bool m_fAppxMode;

HRESULT OnModule(Module * pModule)
{
Expand All @@ -688,7 +703,7 @@ class MulticoreJitRecorderModuleEnumerator : public MulticoreJitModuleEnumerator
}
CONTRACTL_END;

if (MulticoreJitManager::IsSupportedModule(pModule, false, m_fAppxMode))
if (MulticoreJitManager::IsSupportedModule(pModule, false))
{
m_pRecorder->AddModuleDependency(pModule, MulticoreJitManager::GetModuleFileLoadLevel(pModule));
}
Expand All @@ -697,10 +712,9 @@ class MulticoreJitRecorderModuleEnumerator : public MulticoreJitModuleEnumerator
}

public:
MulticoreJitRecorderModuleEnumerator(MulticoreJitRecorder * pRecorder, bool fAppxMode)
MulticoreJitRecorderModuleEnumerator(MulticoreJitRecorder * pRecorder)
{
m_pRecorder = pRecorder;
m_fAppxMode = fAppxMode;
}
};

Expand All @@ -710,6 +724,8 @@ void MulticoreJitRecorder::AddModuleDependency(Module * pModule, FileLoadLevel l
{
STANDARD_VM_CONTRACT;

_ASSERTE(m_ModuleList != nullptr);

MulticoreJitTrace(("AddModuleDependency(%s, %d)", pModule->GetSimpleName(), loadLevel));

_FireEtwMulticoreJitA(W("ADDMODULEDEPENDENCY"), pModule->GetSimpleName(), loadLevel, 0, 0);
Expand All @@ -734,6 +750,8 @@ DWORD MulticoreJitRecorder::EncodeModule(Module * pReferencedModule)
{
STANDARD_VM_CONTRACT;

_ASSERTE(m_ModuleList != nullptr);

unsigned slot = GetOrAddModuleIndex(pReferencedModule);
FileLoadLevel loadLevel = MulticoreJitManager::GetModuleFileLoadLevel(pReferencedModule);

Expand Down Expand Up @@ -834,19 +852,19 @@ void MulticoreJitRecorder::PreRecordFirstMethod()
m_fFirstMethod = false;

{
MulticoreJitRecorderModuleEnumerator enumerator(this, m_fAppxMode);
MulticoreJitRecorderModuleEnumerator enumerator(this);

enumerator.EnumerateLoadedModules(m_pDomain);
}

// When running under Appx or CoreCLR for K, AppDomain is normally not shut down properly (CLR in hybrid case, or Alt-F4 shutdown),
// When running under CoreCLR for K, AppDomain is normally not shut down properly (CLR in hybrid case, or Alt-F4 shutdown),
// So we only allow writing out after profileWriteTimeout seconds
{
// Get the timeout in seconds.
int profileWriteTimeout = (int)CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MultiCoreJitProfileWriteDelay);

#ifndef TARGET_UNIX
// Using the same threadpool timer used by UsageLog to write out profile when running under Appx or CoreCLR.
// Using the same threadpool timer used by UsageLog to write out profile when running under CoreCLR.
MulticoreJitManager & manager = m_pDomain->GetMulticoreJitManager();
s_delayedWriteTimer = CreateThreadpoolTimer(MulticoreJitRecorder::WriteMulticoreJitProfiler, &manager, NULL);

Expand Down Expand Up @@ -876,7 +894,7 @@ void MulticoreJitRecorder::RecordMethodJitOrLoad(MethodDesc * pMethod, bool appl
Module * pModule = pMethod->GetModule_NoLogging();

// Skip methods from non-supported modules
if (! MulticoreJitManager::IsSupportedModule(pModule, true, m_fAppxMode))
if (! MulticoreJitManager::IsSupportedModule(pModule, true))
{
return;
}
Expand Down Expand Up @@ -1019,8 +1037,7 @@ HRESULT MulticoreJitRecorder::StartProfile(const WCHAR * pRoot, const WCHAR * pF

NewHolder<MulticoreJitProfilePlayer> player(new (nothrow) MulticoreJitProfilePlayer(
m_pBinderContext,
nSession,
m_fAppxMode));
nSession));

if (player == NULL)
{
Expand Down Expand Up @@ -1185,13 +1202,17 @@ void MulticoreJitManager::StartProfile(AppDomain * pDomain, ICLRPrivBinder *pBin

if ((pProfile != NULL) && (pProfile[0] != 0)) // Ignore empty file name, just same as StopProfile
{
bool gatherProfile = (int)CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MultiCoreJitNoProfileGather) == 0;

MulticoreJitRecorder * pRecorder = new (nothrow) MulticoreJitRecorder(
pDomain,
pBinderContext,
m_fAppxMode);
gatherProfile);

if (pRecorder != NULL)
{
gatherProfile = pRecorder->CanGatherProfile();

m_pMulticoreJitRecorder = pRecorder;

LONG sessionID = m_ProfileSession.Increment();
Expand All @@ -1200,16 +1221,9 @@ void MulticoreJitManager::StartProfile(AppDomain * pDomain, ICLRPrivBinder *pBin

MulticoreJitTrace(("MulticoreJitRecorder session %d created: %x", sessionID, hr));

if (m_fAppxMode) // In Appx mode, recorder is only enabled when file exists, but header is bad (e.g. zero-length)
if ((hr == COR_E_BADIMAGEFORMAT) || SUCCEEDED(hr)) // Ignore COR_E_BADIMAGEFORMAT, always record new profile
{
if (hr == COR_E_BADIMAGEFORMAT)
{
m_fRecorderActive = true;
}
}
else if ((hr == COR_E_BADIMAGEFORMAT) || SUCCEEDED(hr)) // Otherwise, ignore COR_E_BADIMAGEFORMAT, alway record new profile
{
m_fRecorderActive = true;
m_fRecorderActive = gatherProfile;
}

_FireEtwMulticoreJit(W("STARTPROFILE"), W("Recorder"), m_fRecorderActive, hr, 0);
Expand Down Expand Up @@ -1349,7 +1363,6 @@ MulticoreJitManager::MulticoreJitManager()
m_fSetProfileRootCalled = 0;
m_fAutoStartCalled = 0;
m_fRecorderActive = false;
m_fAppxMode = false;

m_playerLock.Init(CrstMulticoreJitManager, (CrstFlags)(CRST_TAKEN_DURING_SHUTDOWN));
m_MulticoreJitCodeStorage.Init();
Expand Down Expand Up @@ -1382,7 +1395,7 @@ void MulticoreJitManager::RecordModuleLoad(Module * pModule, FileLoadLevel loadL

if (m_fRecorderActive)
{
if(IsSupportedModule(pModule, false, m_fAppxMode)) // Filter out unsupported module
if(IsSupportedModule(pModule, false)) // Filter out unsupported module
{
CrstHolder hold(& m_playerLock);

Expand Down Expand Up @@ -1531,7 +1544,7 @@ void MulticoreJitManager::DisableMulticoreJit()
// static
DWORD MulticoreJitManager::EncodeModuleHelper(void * pModuleContext, Module * pReferencedModule)
{
STANDARD_VM_CONTRACT
STANDARD_VM_CONTRACT;

if (pModuleContext == NULL || pReferencedModule == NULL)
{
Expand Down
4 changes: 1 addition & 3 deletions src/coreclr/vm/multicorejit.h
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,6 @@ class MulticoreJitManager
LONG m_fSetProfileRootCalled; // SetProfileRoot has been called
LONG m_fAutoStartCalled;
bool m_fRecorderActive; // Manager open for recording/event, turned on when initialized properly, turned off when at full capacity
bool m_fAppxMode;
CrstExplicitInit m_playerLock; // Thread protection (accessing m_pMulticoreJitRecorder)
MulticoreJitPlayerStat m_stats; // Statistics: normally gathered by player, written to profile

Expand All @@ -229,7 +228,6 @@ class MulticoreJitManager
m_fSetProfileRootCalled = 0;
m_fAutoStartCalled = 0;
m_fRecorderActive = false;
m_fAppxMode = false;
}

~MulticoreJitManager()
Expand Down Expand Up @@ -299,7 +297,7 @@ class MulticoreJitManager

static void DisableMulticoreJit();

static bool IsSupportedModule(Module * pModule, bool fMethodJit, bool fAppx);
static bool IsSupportedModule(Module * pModule, bool fMethodJit);

static FileLoadLevel GetModuleFileLoadLevel(Module * pModule);

Expand Down
39 changes: 30 additions & 9 deletions src/coreclr/vm/multicorejitimpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ class ModuleRecord

ModuleRecord(unsigned lenName = 0, unsigned lenAssemblyName = 0);

bool MatchWithModule(ModuleVersion & version, bool & gotVersion, Module * pModule, bool & shouldAbort, bool fAppx) const;
bool MatchWithModule(ModuleVersion & version, bool & gotVersion, Module * pModule, bool & shouldAbort) const;

unsigned ModuleNameLen() const
{
Expand Down Expand Up @@ -282,7 +282,6 @@ friend class MulticoreJitRecorder;
MulticoreJitPlayerStat & m_stats;
MulticoreJitCounter & m_appdomainSession;
bool m_shouldAbort;
bool m_fAppxMode;

Thread * m_pThread;

Expand Down Expand Up @@ -320,7 +319,7 @@ friend class MulticoreJitRecorder;

public:

MulticoreJitProfilePlayer(ICLRPrivBinder * pBinderContext, LONG nSession, bool fAppxMode);
MulticoreJitProfilePlayer(ICLRPrivBinder * pBinderContext, LONG nSession);

~MulticoreJitProfilePlayer();

Expand Down Expand Up @@ -619,16 +618,15 @@ class MulticoreJitRecorder
SString m_fullFileName;
MulticoreJitPlayerStat & m_stats;

RecorderModuleInfo m_ModuleList[MAX_MODULES];
RecorderModuleInfo * m_ModuleList;
unsigned m_ModuleCount;
unsigned m_ModuleDepCount;

RecorderInfo m_JitInfoArray[MAX_METHODS];
RecorderInfo * m_JitInfoArray;
LONG m_JitInfoCount;

bool m_fFirstMethod;
bool m_fAborted;
bool m_fAppxMode;

#ifndef TARGET_UNIX
static TP_TIMER * s_delayedWriteTimer;
Expand Down Expand Up @@ -657,21 +655,32 @@ class MulticoreJitRecorder

public:

MulticoreJitRecorder(AppDomain * pDomain, ICLRPrivBinder * pBinderContext, bool fAppxMode)
MulticoreJitRecorder(AppDomain * pDomain, ICLRPrivBinder * pBinderContext, bool fRecorderActive)
: m_stats(pDomain->GetMulticoreJitManager().GetStats())
, m_ModuleList(nullptr)
, m_JitInfoArray(nullptr)
{
LIMITED_METHOD_CONTRACT;

m_pDomain = pDomain;
m_pBinderContext = pBinderContext;

if (fRecorderActive)
{
m_ModuleList = new (nothrow) RecorderModuleInfo[MAX_MODULES];
}
m_ModuleCount = 0;

m_ModuleDepCount = 0;

if (fRecorderActive)
{
m_JitInfoArray = new (nothrow) RecorderInfo[MAX_METHODS];
}
m_JitInfoCount = 0;

m_fFirstMethod = true;
m_fAborted = false;
m_fAppxMode = fAppxMode;


m_stats.Clear();
Expand All @@ -688,14 +697,26 @@ class MulticoreJitRecorder
CloseThreadpoolTimer(pTimer);
}
}
#endif // !TARGET_UNIX

~MulticoreJitRecorder()
{
LIMITED_METHOD_CONTRACT;

delete[] m_ModuleList;
delete[] m_JitInfoArray;

#ifndef TARGET_UNIX
CloseTimer();
}
#endif // !TARGET_UNIX
}

bool CanGatherProfile()
{
LIMITED_METHOD_CONTRACT;

return m_ModuleList != NULL && m_JitInfoArray != NULL;
}

bool IsAtFullCapacity() const
{
Expand Down
Loading

0 comments on commit cbfa7cf

Please sign in to comment.