diff --git a/src/coreclr/md/runtime/mdinternalro.cpp b/src/coreclr/md/runtime/mdinternalro.cpp index 96d7255848552..25bdda172f010 100644 --- a/src/coreclr/md/runtime/mdinternalro.cpp +++ b/src/coreclr/md/runtime/mdinternalro.cpp @@ -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, @@ -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. diff --git a/src/coreclr/vm/appdomain.cpp b/src/coreclr/vm/appdomain.cpp index 51aec1b9e1c69..e5e4104883dc0 100644 --- a/src/coreclr/vm/appdomain.cpp +++ b/src/coreclr/vm/appdomain.cpp @@ -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; diff --git a/src/coreclr/vm/class.cpp b/src/coreclr/vm/class.cpp index 0062632396c95..7ba08c7d35c1c 100644 --- a/src/coreclr/vm/class.cpp +++ b/src/coreclr/vm/class.cpp @@ -1043,6 +1043,8 @@ EEClass::CheckVarianceInSig( void ClassLoader::LoadExactParentAndInterfacesTransitively(MethodTable *pMT) { + INSTRUMENTED_METHOD("ClassLoader::LoadExactParentAndInterfacesTransitively"); + CONTRACTL { STANDARD_VM_CHECK; @@ -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( @@ -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(); @@ -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())) @@ -1200,6 +1210,8 @@ namespace /*static*/ void ClassLoader::LoadExactParents(MethodTable* pMT) { + INSTRUMENTED_METHOD("ClassLoader::LoadExactParents"); + CONTRACT_VOID { STANDARD_VM_CHECK; diff --git a/src/coreclr/vm/clsload.cpp b/src/coreclr/vm/clsload.cpp index ae4aa4f71c9f3..89d9a14021247 100644 --- a/src/coreclr/vm/clsload.cpp +++ b/src/coreclr/vm/clsload.cpp @@ -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; @@ -2055,6 +2057,8 @@ TypeHandle ClassLoader::LoadTypeDefOrRefOrSpecThrowing(Module *pModule, if (TypeFromToken(typeDefOrRefOrSpec) == mdtTypeSpec) { + INSTRUMENTED_METHOD("ClassLoader::LoadTypeDefOrRefOrSpecThrowing / mdTypeSpec"); + ULONG cSig; PCCOR_SIGNATURE pSig; @@ -2081,6 +2085,8 @@ TypeHandle ClassLoader::LoadTypeDefOrRefOrSpecThrowing(Module *pModule, } else { + INSTRUMENTED_METHOD("ClassLoader::LoadTypeDefOrRefOrSpecThrowing / LoadTypeDefOrRefThrowing"); + RETURN (LoadTypeDefOrRefThrowing(pModule, typeDefOrRefOrSpec, fNotFoundAction, fUninstantiated, @@ -2287,6 +2293,7 @@ TypeHandle ClassLoader::LoadTypeDefOrRefThrowing(ModuleBase *pModule, mdToken tokenNotToLoad, ClassLoadLevel level) { + INSTRUMENTED_METHOD("ClassLoader::LoadTypeDefOrRefThrowing"); CONTRACT(TypeHandle) { @@ -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 ? @@ -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, @@ -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); @@ -2846,6 +2859,8 @@ ClassLoader::LoadApproxParentThrowing( /*static*/ TypeHandle ClassLoader::DoIncrementalLoad(TypeKey *pTypeKey, TypeHandle typeHnd, ClassLoadLevel currentLevel) { + INSTRUMENTED_METHOD("ClassLoader::DoIncrementalLoad"); + CONTRACTL { STANDARD_VM_CHECK; @@ -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()); @@ -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; @@ -2907,6 +2925,7 @@ TypeHandle ClassLoader::DoIncrementalLoad(TypeKey *pTypeKey, TypeHandle typeHnd, if (typeHnd.GetLoadLevel() >= CLASS_LOAD_EXACTPARENTS) { + INSTRUMENTED_METHOD("ClassLoader::DoIncrementalLoad / Notify"); Notify(typeHnd); } @@ -3231,6 +3250,9 @@ 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, @@ -3238,7 +3260,12 @@ TypeHandle ClassLoader::LoadTypeHandleForTypeKey(TypeKey *pTypeKey, 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; @@ -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; } @@ -3379,6 +3416,8 @@ ClassLoader::LoadTypeHandleForTypeKey_Body( TypeHandle typeHnd, ClassLoadLevel targetLevel) { + INSTRUMENTED_METHOD("ClassLoader::LoadTypeHandleForTypeKey_Body"); + CONTRACT(TypeHandle) { STANDARD_VM_CHECK; @@ -3545,6 +3584,8 @@ ClassLoader::LoadTypeHandleForTypeKey_Body( EX_TRY { + INSTRUMENTED_METHOD("ClassLoader::LoadTypeHandleForTypeKey_Body / DoIncrementalLoad"); + PendingTypeLoadHolder ptlh(pLoadingEntry); TRIGGERS_TYPELOAD(); diff --git a/src/coreclr/vm/common.h b/src/coreclr/vm/common.h index 6ebe0205951b8..bb75fa6ddd87c 100644 --- a/src/coreclr/vm/common.h +++ b/src/coreclr/vm/common.h @@ -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_ diff --git a/src/coreclr/vm/corhost.cpp b/src/coreclr/vm/corhost.cpp index b85331e00ce8d..b98eb54e322d8 100644 --- a/src/coreclr/vm/corhost.cpp +++ b/src/coreclr/vm/corhost.cpp @@ -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; @@ -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 diff --git a/src/coreclr/vm/methodtablebuilder.cpp b/src/coreclr/vm/methodtablebuilder.cpp index 949040ea47006..ad012b873672e 100644 --- a/src/coreclr/vm/methodtablebuilder.cpp +++ b/src/coreclr/vm/methodtablebuilder.cpp @@ -21,6 +21,129 @@ #include "customattribute.h" #include "typestring.h" +static volatile HANDLE LogFileHandle = INVALID_HANDLE_VALUE; +static volatile int64_t TimerFrequency = 0; + +void DumpInstrumentedMethodTimingInfo() +{ + InstrumentedMethod::DumpAllTiming(); +} + +int64_t GetPreciseTickCount() +{ + int64_t result; + QueryPerformanceCounter((LARGE_INTEGER *)&result); + return result; +} + +void DumpTimingInfo(const char *action, uint32_t threadID, int64_t callCount, int64_t inclusiveTickCount, int64_t subtreeTickCount = 0) +{ + static long timingCallCount = 0; + static const int BufferSize = 1024; + static char buffer[BufferSize]; + static const char *TimingInfoFileName = +#ifdef TARGET_WINDOWS + "\\" +#else + "/" +#endif + "timing-info.txt"; + + if (LogFileHandle == INVALID_HANDLE_VALUE) + { + QueryPerformanceFrequency((LARGE_INTEGER *)&TimerFrequency); + GetCurrentDirectoryA(BufferSize, buffer); + strcat_s(buffer, BufferSize, TimingInfoFileName); + fputs("Output file: ", stdout); + puts(buffer); + + LogFileHandle = CreateFileA(buffer, + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); + + const char *titleLine = "CALLS/INDEX | THREAD | INCLUSIVE SECS | EXCLUSIVE SECS | SUBTREE SECS | EXCLUSIVE % | SUBTREE % | ACTION\n"; + WriteFile(LogFileHandle, titleLine, (DWORD)strlen(titleLine), nullptr, nullptr); + fputs(titleLine, stdout); + } + + int64_t exclusiveTickCount = inclusiveTickCount - subtreeTickCount; + double inclusiveTicksPercentageFactor = 100.0 / (inclusiveTickCount ? inclusiveTickCount : 1); + snprintf(buffer, sizeof(buffer), "%11lld | %8x | %14.9f | %14.9f | %14.9f | %11.2f | %9.2f | %s\n", + callCount, threadID, + inclusiveTickCount / (double)TimerFrequency, + exclusiveTickCount / (double)TimerFrequency, + subtreeTickCount / (double)TimerFrequency, + exclusiveTickCount * inclusiveTicksPercentageFactor, + subtreeTickCount * inclusiveTicksPercentageFactor, + action); + fputs(buffer, stdout); + WriteFile(LogFileHandle, buffer, (DWORD)strlen(buffer), nullptr, nullptr); +} + +void FlushTimingInfo() +{ + if (LogFileHandle != INVALID_HANDLE_VALUE) + { + FlushFileBuffers(LogFileHandle); + CloseHandle(LogFileHandle); + LogFileHandle = INVALID_HANDLE_VALUE; + } +} + +InstrumentedMethod *InstrumentedMethod::s_list = nullptr; + +InstrumentedMethod::InstrumentedMethod(const char *methodName) +{ + _methodName = methodName; + _count = 0; + _ticks = 0; + _next = InterlockedExchangeT(&s_list, this); +} + +void InstrumentedMethod::DumpAllTiming() +{ + const InstrumentedMethod *minMethod = nullptr; + const InstrumentedMethod *nextMethod; + do + { + nextMethod = nullptr; + for (InstrumentedMethod *list = s_list; list != nullptr; list = list->_next) + { + if (minMethod != nullptr && strcmp(list->_methodName, minMethod->_methodName) <= 0) + { + continue; + } + if (nextMethod == nullptr || strcmp(list->_methodName, nextMethod->_methodName) < 0) + { + nextMethod = list; + } + } + if (nextMethod != nullptr) + { + nextMethod->DumpTiming(); + minMethod = nextMethod; + } + } + while (nextMethod != nullptr); +} + +void InstrumentedMethod::DumpTiming() const +{ +#if !defined(DACCESS_COMPILE) + DumpTimingInfo(_methodName, 0, _count, _ticks); +#endif +} + +void InstrumentedMethod::Add(int64_t ticks) +{ + InterlockedIncrement64(&_count); + InterlockedAdd64(&_ticks, ticks); +} + //******************************************************************************* // Helper functions to sort GCdescs by offset (decending order) int __cdecl compareCGCDescSeries(const void *arg1, const void *arg2) @@ -1253,6 +1376,8 @@ MethodTableBuilder::BuildMethodTableThrowing( SigPointer parentInst, WORD cBuildingInterfaceList) { + INSTRUMENTED_METHOD("MethodTableBuilder::BuildMethodTableThrowing"); + CONTRACTL { STANDARD_VM_CHECK; @@ -9273,6 +9398,8 @@ bool InstantiationIsAllTypeVariables(const Instantiation &inst) void MethodTableBuilder::LoadExactInterfaceMap(MethodTable *pMT) { + INSTRUMENTED_METHOD("MethodTableBuilder::LoadExactInterfaceMap"); + CONTRACTL { STANDARD_VM_CHECK; @@ -9339,6 +9466,8 @@ MethodTableBuilder::LoadExactInterfaceMap(MethodTable *pMT) DWORD nAssigned = 0; do { + INSTRUMENTED_METHOD("MethodTableBuilder::LoadExactInterfaceMap / do-while retry"); + nAssigned = 0; retry = false; duplicates = false; @@ -9353,6 +9482,8 @@ MethodTableBuilder::LoadExactInterfaceMap(MethodTable *pMT) InterfaceImplEnum ie(pMT->GetModule(), pMT->GetCl(), NULL); while ((hr = ie.Next()) == S_OK) { + INSTRUMENTED_METHOD("MethodTableBuilder::LoadExactInterfaceMap / do-while retry / LoadTypeDefOrRefOrSpecThrowing"); + MethodTable *pNewIntfMT = ClassLoader::LoadTypeDefOrRefOrSpecThrowing(pMT->GetModule(), ie.CurrentToken(), &typeContext, @@ -9378,6 +9509,8 @@ MethodTableBuilder::LoadExactInterfaceMap(MethodTable *pMT) MethodTable *pItfPossiblyApprox = intIt.GetInterfaceApprox(); if (uninstGenericCase && pItfPossiblyApprox->HasInstantiation() && pItfPossiblyApprox->ContainsGenericVariables()) { + INSTRUMENTED_METHOD("MethodTableBuilder::LoadExactInterfaceMap / HasInstantiation && ContainsGenericVariables"); + // We allow a limited set of interface generic shapes with type variables. In particular, we require the // instantiations to be exactly simple type variables, and to have a relatively small number of generic arguments // so that the fallback instantiating logic works efficiently @@ -9429,6 +9562,8 @@ MethodTableBuilder::LoadExactInterfaceMap(MethodTable *pMT) CONSISTENCY_CHECK(duplicates || (nAssigned == pMT->GetNumInterfaces())); if (duplicates) { + INSTRUMENTED_METHOD("MethodTableBuilder::LoadExactInterfaceMap / duplicates"); + //#LoadExactInterfaceMap_Algorithm2 // Exact interface instantiation loading TECHNIQUE 2 - The exact instantiation has caused some duplicates to // appear in the interface map! This may not be an error: if the duplicates were ones that arose because of @@ -12247,6 +12382,81 @@ BOOL HasLayoutMetadata(Assembly* pAssembly, IMDInternalImport* pInternalImport, return TRUE; } +int64_t GetPreciseTickCount(); + +struct TypeLoadTiming +{ + int64_t InclusiveTicks; + int64_t SubtreeTicks; + TypeHandle Type; + uint32_t Thread; +}; + +const int RING_BUFFER_SIZE = 65536; + +static TypeLoadTiming TypeLoadTimingRingBuffer[RING_BUFFER_SIZE]; +static volatile long TypeLoadRingBufferIndex = 0; + +void RecordTypeLoadTime(const TypeHandle& type, int64_t inclusiveTicks, int64_t subtreeTicks) +{ + long timingIndex = InterlockedIncrement(&TypeLoadRingBufferIndex) - 1; + if (timingIndex >= 0 && timingIndex < RING_BUFFER_SIZE) + { + TypeLoadTimingRingBuffer[timingIndex].Thread = GetCurrentThreadId(); + TypeLoadTimingRingBuffer[timingIndex].InclusiveTicks = inclusiveTicks; + TypeLoadTimingRingBuffer[timingIndex].SubtreeTicks = subtreeTicks; + TypeLoadTimingRingBuffer[timingIndex].Type = type; + } +} + +void DumpTypeLoadTimingInfo() +{ + HashMap threadMap; + threadMap.Init(/*cbInitialSize*/ 32, /*fAsyncMode*/ false, /*pLock*/ nullptr); + + for (int32_t ringBufferIndex = 0; ringBufferIndex < TypeLoadRingBufferIndex; ringBufferIndex++) + { + const TypeLoadTiming& timing = TypeLoadTimingRingBuffer[ringBufferIndex]; + SString typeName; + timing.Type.GetName(typeName); + DumpTimingInfo(typeName.GetUTF8(), timing.Thread, ringBufferIndex, timing.InclusiveTicks, timing.SubtreeTicks); + if (threadMap.LookupValue(timing.Thread, timing.Thread) == INVALIDENTRY) + { + threadMap.InsertValue(timing.Thread, timing.Thread); + } + } + + int32_t totalCount = 0; + int64_t totalInclusiveTicks = 0; + int64_t totalSubtreeTicks = 0; + for (HashMap::Iterator it = threadMap.begin(); !it.end(); ++it) + { + uint32_t threadID = (uint32_t)it.GetKey(); + int32_t threadCount = 0; + int64_t threadInclusiveTicks = 0; + int64_t threadSubtreeTicks = 0; + for (int32_t ringBufferIndex = 0; ringBufferIndex < TypeLoadRingBufferIndex; ringBufferIndex++) + { + const TypeLoadTiming& timing = TypeLoadTimingRingBuffer[ringBufferIndex]; + if (timing.Thread == threadID) + { + threadInclusiveTicks += timing.InclusiveTicks; + threadSubtreeTicks += timing.SubtreeTicks; + threadCount++; + } + } + char buffer[100]; + sprintf(buffer, "LoadTypeHandleForTypeKey @ %08x", threadID); + DumpTimingInfo(buffer, threadID, threadCount, threadInclusiveTicks, threadSubtreeTicks); + + totalCount += threadCount; + totalInclusiveTicks += threadInclusiveTicks; + totalSubtreeTicks += threadSubtreeTicks; + } + + DumpTimingInfo("LoadTypeHandleForTypeKey", GetCurrentThreadId(), totalCount, totalInclusiveTicks, totalSubtreeTicks); +} + //--------------------------------------------------------------------------------------- // // This service is called for normal classes -- and for the pseudo class we invent to @@ -12260,6 +12470,10 @@ ClassLoader::CreateTypeHandleForTypeDefThrowing( Instantiation inst, AllocMemTracker * pamTracker) { + INSTRUMENTED_METHOD("ClassLoader::CreateTypeHandleForTypeDefThrowing"); + + int64_t startTicks = GetPreciseTickCount(); + CONTRACT(TypeHandle) { STANDARD_VM_CHECK; diff --git a/src/coreclr/vm/nativeimage.cpp b/src/coreclr/vm/nativeimage.cpp index 49f797f896254..11f721e9f7101 100644 --- a/src/coreclr/vm/nativeimage.cpp +++ b/src/coreclr/vm/nativeimage.cpp @@ -62,6 +62,8 @@ NativeImage::NativeImage(AssemblyBinder *pAssemblyBinder, PEImageLayout *pImageL void NativeImage::Initialize(READYTORUN_HEADER *pHeader, LoaderAllocator *pLoaderAllocator, AllocMemTracker *pamTracker) { + INSTRUMENTED_METHOD("NativeImage::Initialize"); + LoaderHeap *pHeap = pLoaderAllocator->GetHighFrequencyHeap(); m_pReadyToRunInfo = new ReadyToRunInfo(/*pModule*/ NULL, pLoaderAllocator, m_pImageLayout, pHeader, this, pamTracker); @@ -115,6 +117,8 @@ NativeImage *NativeImage::Open( LoaderAllocator *pLoaderAllocator, /* out */ bool *isNewNativeImage) { + INSTRUMENTED_METHOD("NativeImage::Open"); + STANDARD_VM_CONTRACT; NativeImage *pExistingImage = AppDomain::GetCurrentDomain()->GetNativeImage(nativeImageFileName); @@ -263,6 +267,8 @@ NativeImage *NativeImage::Open( #ifndef DACCESS_COMPILE Assembly *NativeImage::LoadManifestAssembly(uint32_t rowid, DomainAssembly *pParentAssembly) { + INSTRUMENTED_METHOD("NativeImage::LoadManifestAssembly"); + STANDARD_VM_CONTRACT; AssemblySpec spec; @@ -274,6 +280,8 @@ Assembly *NativeImage::LoadManifestAssembly(uint32_t rowid, DomainAssembly *pPar #ifndef DACCESS_COMPILE PTR_READYTORUN_CORE_HEADER NativeImage::GetComponentAssemblyHeader(LPCUTF8 simpleName) { + INSTRUMENTED_METHOD("NativeImage::GetComponentAssemblyHeader"); + STANDARD_VM_CONTRACT; const AssemblyNameIndex *assemblyNameIndex = m_assemblySimpleNameToIndexMap.LookupPtr(simpleName); @@ -291,6 +299,8 @@ PTR_READYTORUN_CORE_HEADER NativeImage::GetComponentAssemblyHeader(LPCUTF8 simpl #ifndef DACCESS_COMPILE IMDInternalImport *NativeImage::LoadManifestMetadata() { + INSTRUMENTED_METHOD("NativeImage::LoadManifestMetadata"); + STANDARD_VM_CONTRACT; IMAGE_DATA_DIRECTORY *pMeta = m_pReadyToRunInfo->FindSection(ReadyToRunSectionType::ManifestMetadata);