Skip to content
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

[NO-MERGE] CoreCLR runtime instrumentation for measuring type load performance #95288

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions src/coreclr/md/runtime/mdinternalro.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -798,7 +798,6 @@ HRESULT MDInternalRO::FindMethodDef( // S_OK or error.
ULONG cbSigBlob, // [IN] count of bytes in the signature blob
mdMethodDef *pmethoddef) // Put MemberDef token here.
{

return FindMethodDefUsingCompare(classdef,
szName,
pvSigBlob,
Expand Down Expand Up @@ -1227,7 +1226,6 @@ HRESULT MDInternalRO::GetItemGuid( // return hresult
mdToken tkObj, // given item
CLSID *pGuid)
{

HRESULT hr; // A result.
const BYTE *pBlob = NULL; // Blob with dispid.
ULONG cbBlob; // Length of blob.
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/vm/appdomain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2562,6 +2562,8 @@ CHECK AppDomain::CheckCanExecuteManagedCode(MethodDesc* pMD)
void AppDomain::LoadDomainAssembly(DomainAssembly *pFile,
FileLoadLevel targetLevel)
{
INSTRUMENTED_METHOD("AppDomain::LoadDomainAssembly");

CONTRACTL
{
if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
Expand Down
14 changes: 13 additions & 1 deletion src/coreclr/vm/class.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1043,6 +1043,8 @@ EEClass::CheckVarianceInSig(
void
ClassLoader::LoadExactParentAndInterfacesTransitively(MethodTable *pMT)
{
INSTRUMENTED_METHOD("ClassLoader::LoadExactParentAndInterfacesTransitively");

CONTRACTL
{
STANDARD_VM_CHECK;
Expand All @@ -1058,6 +1060,8 @@ ClassLoader::LoadExactParentAndInterfacesTransitively(MethodTable *pMT)

if (pParentMT != NULL && pParentMT->HasInstantiation())
{
INSTRUMENTED_METHOD("ClassLoader::LoadExactParentAndInterfacesTransitively / LoadTypeDefOrRefOrSpecThrowing");

// Fill in exact parent if it's instantiated
mdToken crExtends;
IfFailThrow(pInternalImport->GetTypeDefProps(
Expand Down Expand Up @@ -1088,12 +1092,15 @@ ClassLoader::LoadExactParentAndInterfacesTransitively(MethodTable *pMT)

if (pParentMT != NULL)
{
INSTRUMENTED_METHOD("ClassLoader::LoadExactParentAndInterfacesTransitively / EnsureLoaded");
EnsureLoaded(pParentMT, CLASS_LOAD_EXACTPARENTS);
}


if (pParentMT != NULL && pParentMT->HasPerInstInfo())
{
INSTRUMENTED_METHOD("ClassLoader::LoadExactParentAndInterfacesTransitively / CopyDictionaryPointers");

// Copy down all inherited dictionary pointers which we
// could not embed.
DWORD nDicts = pParentMT->GetNumDicts();
Expand All @@ -1106,7 +1113,10 @@ ClassLoader::LoadExactParentAndInterfacesTransitively(MethodTable *pMT)
}
}

MethodTableBuilder::LoadExactInterfaceMap(pMT);
{
INSTRUMENTED_METHOD("ClassLoader::LoadExactParentAndInterfacesTransitively / LoadExactInterfaceMap");
MethodTableBuilder::LoadExactInterfaceMap(pMT);
}

#ifdef _DEBUG
if (g_pConfig->ShouldDumpOnClassLoad(pMT->GetDebugClassName()))
Expand Down Expand Up @@ -1200,6 +1210,8 @@ namespace
/*static*/
void ClassLoader::LoadExactParents(MethodTable* pMT)
{
INSTRUMENTED_METHOD("ClassLoader::LoadExactParents");

CONTRACT_VOID
{
STANDARD_VM_CHECK;
Expand Down
43 changes: 42 additions & 1 deletion src/coreclr/vm/clsload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2039,6 +2039,8 @@ TypeHandle ClassLoader::LoadTypeDefOrRefOrSpecThrowing(Module *pModule,
const Substitution *pSubst,
MethodTable *pMTInterfaceMapOwner)
{
INSTRUMENTED_METHOD("ClassLoader::LoadTypeDefOrRefOrSpecThrowing");

CONTRACT(TypeHandle)
{
if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
Expand All @@ -2055,6 +2057,8 @@ TypeHandle ClassLoader::LoadTypeDefOrRefOrSpecThrowing(Module *pModule,

if (TypeFromToken(typeDefOrRefOrSpec) == mdtTypeSpec)
{
INSTRUMENTED_METHOD("ClassLoader::LoadTypeDefOrRefOrSpecThrowing / mdTypeSpec");

ULONG cSig;
PCCOR_SIGNATURE pSig;

Expand All @@ -2081,6 +2085,8 @@ TypeHandle ClassLoader::LoadTypeDefOrRefOrSpecThrowing(Module *pModule,
}
else
{
INSTRUMENTED_METHOD("ClassLoader::LoadTypeDefOrRefOrSpecThrowing / LoadTypeDefOrRefThrowing");

RETURN (LoadTypeDefOrRefThrowing(pModule, typeDefOrRefOrSpec,
fNotFoundAction,
fUninstantiated,
Expand Down Expand Up @@ -2287,6 +2293,7 @@ TypeHandle ClassLoader::LoadTypeDefOrRefThrowing(ModuleBase *pModule,
mdToken tokenNotToLoad,
ClassLoadLevel level)
{
INSTRUMENTED_METHOD("ClassLoader::LoadTypeDefOrRefThrowing");

CONTRACT(TypeHandle)
{
Expand Down Expand Up @@ -2356,6 +2363,8 @@ TypeHandle ClassLoader::LoadTypeDefOrRefThrowing(ModuleBase *pModule,

else if (tokType == mdtTypeRef)
{
INSTRUMENTED_METHOD("ClassLoader::LoadTypeDefOrRefThrowing / TypeRef");

BOOL fNoResolutionScope;
Module *pFoundModule = Assembly::FindModuleByTypeRef(pModule, typeDefOrRef,
tokenNotToLoad==tdAllTypes ?
Expand All @@ -2382,6 +2391,8 @@ TypeHandle ClassLoader::LoadTypeDefOrRefThrowing(ModuleBase *pModule,
{
if (fNoResolutionScope && pFoundModule->IsFullModule())
{
INSTRUMENTED_METHOD("ClassLoader::LoadTypeDefOrRefThrowing / LoadTypeByNameThrowing");

// Everett C++ compiler can generate a TypeRef with RS=0
// without respective TypeDef for unmanaged valuetypes,
// referenced only by pointers to them,
Expand All @@ -2401,6 +2412,8 @@ TypeHandle ClassLoader::LoadTypeDefOrRefThrowing(ModuleBase *pModule,
}
else
{
INSTRUMENTED_METHOD("ClassLoader::LoadTypeDefOrRefThrowing / LoadTypeHandleThrowIfFailed");

NameHandle nameHandle(pModule, typeDefOrRef);
nameHandle.SetName(pszNameSpace, pszClassName);
nameHandle.SetTokenNotToLoad(tokenNotToLoad);
Expand Down Expand Up @@ -2846,6 +2859,8 @@ ClassLoader::LoadApproxParentThrowing(
/*static*/
TypeHandle ClassLoader::DoIncrementalLoad(TypeKey *pTypeKey, TypeHandle typeHnd, ClassLoadLevel currentLevel)
{
INSTRUMENTED_METHOD("ClassLoader::DoIncrementalLoad");

CONTRACTL
{
STANDARD_VM_CHECK;
Expand Down Expand Up @@ -2873,6 +2888,8 @@ TypeHandle ClassLoader::DoIncrementalLoad(TypeKey *pTypeKey, TypeHandle typeHnd,
// or at least level CLASS_LOAD_APPROXPARENTS (if creating type for the first time)
case CLASS_LOAD_BEGIN :
{
INSTRUMENTED_METHOD("ClassLoader::DoIncrementalLoad / CLASS_LOAD_BEGIN");

AllocMemTracker amTracker;
typeHnd = CreateTypeHandleForTypeKey(pTypeKey, &amTracker);
CONSISTENCY_CHECK(!typeHnd.IsNull());
Expand All @@ -2894,6 +2911,7 @@ TypeHandle ClassLoader::DoIncrementalLoad(TypeKey *pTypeKey, TypeHandle typeHnd,
case CLASS_LOAD_APPROXPARENTS :
if (!typeHnd.IsTypeDesc())
{
INSTRUMENTED_METHOD("ClassLoader::DoIncrementalLoad / CLASS_LOAD_APPROXPARENTS");
LoadExactParents(typeHnd.AsMethodTable());
}
break;
Expand All @@ -2907,6 +2925,7 @@ TypeHandle ClassLoader::DoIncrementalLoad(TypeKey *pTypeKey, TypeHandle typeHnd,

if (typeHnd.GetLoadLevel() >= CLASS_LOAD_EXACTPARENTS)
{
INSTRUMENTED_METHOD("ClassLoader::DoIncrementalLoad / Notify");
Notify(typeHnd);
}

Expand Down Expand Up @@ -3231,14 +3250,22 @@ static void PushFinalLevels(TypeHandle typeHnd, ClassLoadLevel targetLevel, cons
}
}

void RecordTypeLoadTime(const TypeHandle& type, int64_t inclusiveTicks, int64_t subtreeTicks);

thread_local int64_t *PendingTypeLoad = nullptr;

//
TypeHandle ClassLoader::LoadTypeHandleForTypeKey(TypeKey *pTypeKey,
TypeHandle typeHnd,
ClassLoadLevel targetLevel/*=CLASS_LOADED*/,
const InstantiationContext *pInstContext/*=NULL*/)
{

INSTRUMENTED_METHOD("ClassLoader::LoadTypeHandleForTypeKey");
int64_t startTicks = GetPreciseTickCount();
int64_t *parentTypeLoad = PendingTypeLoad;
int64_t subtreeTypeLoadTicks = 0;
PendingTypeLoad = &subtreeTypeLoadTicks;

CONTRACTL
{
INSTANCE_CHECK;
Expand Down Expand Up @@ -3286,6 +3313,16 @@ TypeHandle ClassLoader::LoadTypeHandleForTypeKey(TypeKey *pTypeKey,
}
#endif

int64_t inclusiveTicks = GetPreciseTickCount() - startTicks;
RecordTypeLoadTime(typeHnd, inclusiveTicks, subtreeTypeLoadTicks);

if (parentTypeLoad != nullptr)
{
*parentTypeLoad += inclusiveTicks;
}

PendingTypeLoad = parentTypeLoad;

return typeHnd;
}

Expand Down Expand Up @@ -3379,6 +3416,8 @@ ClassLoader::LoadTypeHandleForTypeKey_Body(
TypeHandle typeHnd,
ClassLoadLevel targetLevel)
{
INSTRUMENTED_METHOD("ClassLoader::LoadTypeHandleForTypeKey_Body");

CONTRACT(TypeHandle)
{
STANDARD_VM_CHECK;
Expand Down Expand Up @@ -3545,6 +3584,8 @@ ClassLoader::LoadTypeHandleForTypeKey_Body(

EX_TRY
{
INSTRUMENTED_METHOD("ClassLoader::LoadTypeHandleForTypeKey_Body / DoIncrementalLoad");

PendingTypeLoadHolder ptlh(pLoadingEntry);

TRIGGERS_TYPELOAD();
Expand Down
54 changes: 54 additions & 0 deletions src/coreclr/vm/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,60 @@ extern DummyGlobalContract ___contract;

void LogErrorToHost(const char* format, ...);

int64_t GetPreciseTickCount();

class InstrumentedMethod
{
public:
class Execution
{
private:
InstrumentedMethod *_instrumentedMethod;
int64_t _startTicks;

public:
Execution(InstrumentedMethod *method)
: _instrumentedMethod(method)
{
#ifndef DACCESS_COMPILE
_startTicks = GetPreciseTickCount();
#endif
}

~Execution()
{
#ifndef DACCESS_COMPILE
_instrumentedMethod->Add(GetPreciseTickCount() - _startTicks);
#endif
}
};

private:
static InstrumentedMethod *s_list;

const char *_methodName;
int64_t _count;
int64_t _ticks;
InstrumentedMethod *_next;

public:
InstrumentedMethod(const char *methodName);

static void DumpAllTiming();
void Add(int64_t ticks);

private:
void DumpTiming() const;
};

#ifndef DACCESS_COMPILE
#define INSTRUMENTED_METHOD(name) \
static InstrumentedMethod s_instrumentedMethod(name); \
InstrumentedMethod::Execution methodExecution(&s_instrumentedMethod);
#else
#define INSTRUMENTED_METHOD(name)
#endif

#endif // !_common_h_


9 changes: 9 additions & 0 deletions src/coreclr/vm/corhost.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -837,6 +837,11 @@ STDMETHODIMP CorHost2::UnloadAppDomain(DWORD dwDomainId, BOOL fWaitUntilDone)
return UnloadAppDomain2(dwDomainId, fWaitUntilDone, nullptr);
}

void DumpAssemblyLoadTimingInfo();
void DumpTypeLoadTimingInfo();
void DumpInstrumentedMethodTimingInfo();
void FlushTimingInfo();

STDMETHODIMP CorHost2::UnloadAppDomain2(DWORD dwDomainId, BOOL fWaitUntilDone, int *pLatchedExitCode)
{
WRAPPER_NO_CONTRACT;
Expand Down Expand Up @@ -872,6 +877,10 @@ STDMETHODIMP CorHost2::UnloadAppDomain2(DWORD dwDomainId, BOOL fWaitUntilDone, i
if (1 == refCount)
{
// Stop coreclr on unload.
DumpTypeLoadTimingInfo();
DumpInstrumentedMethodTimingInfo();
FlushTimingInfo();

EEShutDown(FALSE);
}
else
Expand Down
Loading
Loading