From d58b1cade30a6aaf94d187fa0d5f939c3e561e29 Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Fri, 13 Sep 2024 16:03:41 -0700 Subject: [PATCH] Fix perf problems found in investigation of issue #107728 (#107806) - `CheckRunClassInitThrowing` didn't check to see if the class had been initialized before taking a lock - `EnsureTlsIndexAllocated` didn't check if the Tls index had been allocated before setting the flag via an expensive Interlocked call to indicate that it had been allocated - And finally `JIT_GetNonGCThreadStaticBaseOptimized` and `JIT_GetGCThreadStaticBaseOptimized` were missing the fast paths which avoided even calling those apis at all. Perf with a small benchmark which does complex multithreaded work... | Runtime | Time | | ---- | ---- | | .NET 8 | 00.9414682 s | | .NET 9 before this fix | 22.8079382 | | .NET 9 with this fix | 00.2004539 | Fixes #107728 --- src/coreclr/vm/jithelpers.cpp | 12 ++++++++++++ src/coreclr/vm/methodtable.cpp | 10 +++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index 482556672942a..5777d7feea582 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -901,6 +901,12 @@ HCIMPL1(void*, JIT_GetNonGCThreadStaticBaseOptimized, UINT32 staticBlockIndex) FCALL_CONTRACT; + staticBlock = GetThreadLocalStaticBaseIfExistsAndInitialized(staticBlockIndex); + if (staticBlock != NULL) + { + return staticBlock; + } + HELPER_METHOD_FRAME_BEGIN_RET_0(); // Set up a frame TLSIndex tlsIndex(staticBlockIndex); // Check if the class constructor needs to be run @@ -975,6 +981,12 @@ HCIMPL1(void*, JIT_GetGCThreadStaticBaseOptimized, UINT32 staticBlockIndex) FCALL_CONTRACT; + staticBlock = GetThreadLocalStaticBaseIfExistsAndInitialized(staticBlockIndex); + if (staticBlock != NULL) + { + return staticBlock; + } + HELPER_METHOD_FRAME_BEGIN_RET_0(); // Set up a frame TLSIndex tlsIndex(staticBlockIndex); diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index 3d2402a4dfa2f..ba0e9ab987b84 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -3797,8 +3797,8 @@ void MethodTable::CheckRunClassInitThrowing() // To find GC hole easier... TRIGGERSGC(); - // Don't initialize shared generic instantiations (e.g. MyClass<__Canon>) - if (IsSharedByGenericInstantiations()) + // Don't initialize shared generic instantiations (e.g. MyClass<__Canon>), or an already initialized MethodTable + if (IsClassInited() || IsSharedByGenericInstantiations()) return; _ASSERTE(!ContainsGenericVariables()); @@ -3903,7 +3903,11 @@ void MethodTable::EnsureTlsIndexAllocated() CONTRACTL_END; PTR_MethodTableAuxiliaryData pAuxiliaryData = GetAuxiliaryDataForWrite(); - if (!pAuxiliaryData->IsTlsIndexAllocated() && GetNumThreadStaticFields() > 0) + + if (pAuxiliaryData->IsTlsIndexAllocated()) + return; + + if (GetNumThreadStaticFields() > 0) { ThreadStaticsInfo *pThreadStaticsInfo = MethodTableAuxiliaryData::GetThreadStaticsInfo(GetAuxiliaryDataForWrite()); // Allocate space for normal statics if we might have them