Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.

Commit

Permalink
Reduce Monitor spinning
Browse files Browse the repository at this point in the history
  • Loading branch information
kouvel committed Oct 31, 2017
1 parent b25fb6c commit c02b433
Show file tree
Hide file tree
Showing 14 changed files with 79 additions and 162 deletions.
1 change: 1 addition & 0 deletions src/inc/clrconfigvalues.h
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,7 @@ RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_SpinLimitProcCap, W("SpinLimitProcCap"), 0x
RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_SpinLimitProcFactor, W("SpinLimitProcFactor"), 0x4E20, "Hex value specifying the multiplier on NumProcs to use when calculating the maximum spin duration", EEConfig_default)
RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_SpinLimitConstant, W("SpinLimitConstant"), 0x0, "Hex value specifying the constant to add when calculating the maximum spin duration", EEConfig_default)
RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_SpinRetryCount, W("SpinRetryCount"), 0xA, "Hex value specifying the number of times the entire spin process is repeated (when applicable)", EEConfig_default)
RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_Monitor_SpinCount, W("Monitor_SpinCount"), 0x1e, "Hex value specifying the maximum number of spin iterations Monitor may perform upon contention on acquiring the lock before waiting.", EEConfig_default)

//
// Native Binder
Expand Down
1 change: 1 addition & 0 deletions src/inc/utilcode.h
Original file line number Diff line number Diff line change
Expand Up @@ -5515,6 +5515,7 @@ struct SpinConstants
DWORD dwMaximumDuration;
DWORD dwBackoffFactor;
DWORD dwRepetitions;
DWORD dwMonitorSpinCount;
};

extern SpinConstants g_SpinConstants;
Expand Down
3 changes: 2 additions & 1 deletion src/utilcode/utsem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ SpinConstants g_SpinConstants = {
50, // dwInitialDuration
40000, // dwMaximumDuration - ideally (20000 * max(2, numProc)) ... updated in code:InitializeSpinConstants_NoHost
3, // dwBackoffFactor
10 // dwRepetitions
10, // dwRepetitions
0 // dwMonitorSpinCount
};

inline void InitializeSpinConstants_NoHost()
Expand Down
16 changes: 0 additions & 16 deletions src/vm/amd64/asmconstants.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,22 +190,6 @@ ASMCONSTANT_OFFSETOF_ASSERT(DelegateObject, _methodPtr);
#define OFFSETOF__DelegateObject___target 0x08
ASMCONSTANT_OFFSETOF_ASSERT(DelegateObject, _target);

#define OFFSETOF__g_SystemInfo__dwNumberOfProcessors 0x20
ASMCONSTANTS_C_ASSERT(OFFSETOF__g_SystemInfo__dwNumberOfProcessors
== offsetof(SYSTEM_INFO, dwNumberOfProcessors));

#define OFFSETOF__g_SpinConstants__dwInitialDuration 0x0
ASMCONSTANTS_C_ASSERT(OFFSETOF__g_SpinConstants__dwInitialDuration
== offsetof(SpinConstants, dwInitialDuration));

#define OFFSETOF__g_SpinConstants__dwMaximumDuration 0x4
ASMCONSTANTS_C_ASSERT(OFFSETOF__g_SpinConstants__dwMaximumDuration
== offsetof(SpinConstants, dwMaximumDuration));

#define OFFSETOF__g_SpinConstants__dwBackoffFactor 0x8
ASMCONSTANTS_C_ASSERT(OFFSETOF__g_SpinConstants__dwBackoffFactor
== offsetof(SpinConstants, dwBackoffFactor));

#define OFFSETOF__MethodTable__m_dwFlags 0x00
ASMCONSTANTS_C_ASSERT(OFFSETOF__MethodTable__m_dwFlags
== offsetof(MethodTable, m_dwFlags));
Expand Down
2 changes: 2 additions & 0 deletions src/vm/eeconfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ HRESULT EEConfig::Init()
dwSpinLimitProcFactor = 0x4E20;
dwSpinLimitConstant = 0x0;
dwSpinRetryCount = 0xA;
dwMonitorSpinCount = 0;

iJitOptimizeType = OPT_DEFAULT;
fJitFramed = false;
Expand Down Expand Up @@ -1026,6 +1027,7 @@ HRESULT EEConfig::sync()
dwSpinLimitProcFactor = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_SpinLimitProcFactor);
dwSpinLimitConstant = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_SpinLimitConstant);
dwSpinRetryCount = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_SpinRetryCount);
dwMonitorSpinCount = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_Monitor_SpinCount);

fJitFramed = (GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_JitFramed, fJitFramed) != 0);
fJitAlignLoops = (GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_JitAlignLoops, fJitAlignLoops) != 0);
Expand Down
2 changes: 2 additions & 0 deletions src/vm/eeconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@ class EEConfig
DWORD SpinLimitProcFactor(void) const {LIMITED_METHOD_CONTRACT; return dwSpinLimitProcFactor; }
DWORD SpinLimitConstant(void) const {LIMITED_METHOD_CONTRACT; return dwSpinLimitConstant; }
DWORD SpinRetryCount(void) const {LIMITED_METHOD_CONTRACT; return dwSpinRetryCount; }
DWORD MonitorSpinCount(void) const {LIMITED_METHOD_CONTRACT; return dwMonitorSpinCount; }

// Jit-config

Expand Down Expand Up @@ -978,6 +979,7 @@ class EEConfig
DWORD dwSpinLimitProcFactor;
DWORD dwSpinLimitConstant;
DWORD dwSpinRetryCount;
DWORD dwMonitorSpinCount;

#ifdef VERIFY_HEAP
int iGCHeapVerify;
Expand Down
14 changes: 0 additions & 14 deletions src/vm/i386/asmconstants.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,20 +65,6 @@ ASMCONSTANTS_C_ASSERT(CONTEXT_Eip == offsetof(CONTEXT,Eip))
#define CONTEXT_Esp 0xc4
ASMCONSTANTS_C_ASSERT(CONTEXT_Esp == offsetof(CONTEXT,Esp))

// SYSTEM_INFO from rotor_pal.h
#define SYSTEM_INFO_dwNumberOfProcessors 20
ASMCONSTANTS_C_ASSERT(SYSTEM_INFO_dwNumberOfProcessors == offsetof(SYSTEM_INFO,dwNumberOfProcessors))

// SpinConstants from clr/src/vars.h
#define SpinConstants_dwInitialDuration 0
ASMCONSTANTS_C_ASSERT(SpinConstants_dwInitialDuration == offsetof(SpinConstants,dwInitialDuration))

#define SpinConstants_dwMaximumDuration 4
ASMCONSTANTS_C_ASSERT(SpinConstants_dwMaximumDuration == offsetof(SpinConstants,dwMaximumDuration))

#define SpinConstants_dwBackoffFactor 8
ASMCONSTANTS_C_ASSERT(SpinConstants_dwBackoffFactor == offsetof(SpinConstants,dwBackoffFactor))

#ifndef WIN64EXCEPTIONS
// EHContext from clr/src/vm/i386/cgencpu.h
#define EHContext_Eax 0x00
Expand Down
83 changes: 3 additions & 80 deletions src/vm/jithelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4432,39 +4432,13 @@ NOINLINE static void JIT_MonEnter_Helper(Object* obj, BYTE* pbLockTaken, LPVOID
HCIMPL_MONHELPER(JIT_MonEnterWorker_Portable, Object* obj)
{
FCALL_CONTRACT;

AwareLock::EnterHelperResult result;
Thread * pCurThread;

if (obj == NULL)
{
goto FramedLockHelper;
}

pCurThread = GetThread();

if (pCurThread->CatchAtSafePointOpportunistic())
{
goto FramedLockHelper;
}

result = obj->EnterObjMonitorHelper(pCurThread);
if (result == AwareLock::EnterHelperResult_Entered)
if (obj != nullptr && obj->TryEnterObjMonitorSpinHelper())
{
MONHELPER_STATE(*pbLockTaken = 1);
return;
}
if (result == AwareLock::EnterHelperResult_Contention)
{
result = obj->EnterObjMonitorHelperSpin(pCurThread);
if (result == AwareLock::EnterHelperResult_Entered)
{
MONHELPER_STATE(*pbLockTaken = 1);
return;
}
}

FramedLockHelper:
FC_INNER_RETURN_VOID(JIT_MonEnter_Helper(obj, MONHELPER_ARG, GetEEFuncEntryPointMacro(JIT_MonEnter)));
}
HCIMPLEND
Expand All @@ -4473,36 +4447,11 @@ HCIMPL1(void, JIT_MonEnter_Portable, Object* obj)
{
FCALL_CONTRACT;

Thread * pCurThread;
AwareLock::EnterHelperResult result;

if (obj == NULL)
{
goto FramedLockHelper;
}

pCurThread = GetThread();

if (pCurThread->CatchAtSafePointOpportunistic())
{
goto FramedLockHelper;
}

result = obj->EnterObjMonitorHelper(pCurThread);
if (result == AwareLock::EnterHelperResult_Entered)
if (obj != nullptr && obj->TryEnterObjMonitorSpinHelper())
{
return;
}
if (result == AwareLock::EnterHelperResult_Contention)
{
result = obj->EnterObjMonitorHelperSpin(pCurThread);
if (result == AwareLock::EnterHelperResult_Entered)
{
return;
}
}

FramedLockHelper:
FC_INNER_RETURN_VOID(JIT_MonEnter_Helper(obj, NULL, GetEEFuncEntryPointMacro(JIT_MonEnter)));
}
HCIMPLEND
Expand All @@ -4511,38 +4460,12 @@ HCIMPL2(void, JIT_MonReliableEnter_Portable, Object* obj, BYTE* pbLockTaken)
{
FCALL_CONTRACT;

Thread * pCurThread;
AwareLock::EnterHelperResult result;

if (obj == NULL)
{
goto FramedLockHelper;
}

pCurThread = GetThread();

if (pCurThread->CatchAtSafePointOpportunistic())
{
goto FramedLockHelper;
}

result = obj->EnterObjMonitorHelper(pCurThread);
if (result == AwareLock::EnterHelperResult_Entered)
if (obj != nullptr && obj->TryEnterObjMonitorSpinHelper())
{
*pbLockTaken = 1;
return;
}
if (result == AwareLock::EnterHelperResult_Contention)
{
result = obj->EnterObjMonitorHelperSpin(pCurThread);
if (result == AwareLock::EnterHelperResult_Entered)
{
*pbLockTaken = 1;
return;
}
}

FramedLockHelper:
FC_INNER_RETURN_VOID(JIT_MonEnter_Helper(obj, pbLockTaken, GetEEFuncEntryPointMacro(JIT_MonReliableEnter)));
}
HCIMPLEND
Expand Down
2 changes: 2 additions & 0 deletions src/vm/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,8 @@ class Object
return GetHeader()->TryEnterObjMonitor(timeOut);
}

bool TryEnterObjMonitorSpinHelper();

FORCEINLINE AwareLock::EnterHelperResult EnterObjMonitorHelper(Thread* pCurThread)
{
WRAPPER_NO_CONTRACT;
Expand Down
36 changes: 34 additions & 2 deletions src/vm/object.inl
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,40 @@ inline void Object::EnumMemoryRegions(void)
// the enumeration to the MethodTable.
}

#endif // #ifdef DACCESS_COMPILE

#else // !DACCESS_COMPILE

FORCEINLINE bool Object::TryEnterObjMonitorSpinHelper()
{
CONTRACTL{
SO_TOLERANT;
NOTHROW;
GC_NOTRIGGER;
MODE_COOPERATIVE;
} CONTRACTL_END;

Thread *pCurThread = GetThread();
if (pCurThread->CatchAtSafePointOpportunistic())
{
return false;
}

AwareLock::EnterHelperResult result = EnterObjMonitorHelper(pCurThread);
if (result == AwareLock::EnterHelperResult_Entered)
{
return true;
}
if (result == AwareLock::EnterHelperResult_Contention)
{
result = EnterObjMonitorHelperSpin(pCurThread);
if (result == AwareLock::EnterHelperResult_Entered)
{
return true;
}
}
return false;
}

#endif // DACCESS_COMPILE

inline TypeHandle ArrayBase::GetTypeHandle() const
{
Expand Down
54 changes: 19 additions & 35 deletions src/vm/syncblk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1917,11 +1917,11 @@ AwareLock::EnterHelperResult ObjHeader::EnterObjMonitorHelperSpin(Thread* pCurTh
return AwareLock::EnterHelperResult_Contention;
}

DWORD maxSpinCount = g_SpinConstants.dwMaximumDuration;
DWORD backoffFactor = g_SpinConstants.dwBackoffFactor;
for (DWORD spinCount = g_SpinConstants.dwInitialDuration; spinCount <= maxSpinCount; spinCount *= backoffFactor)
YieldProcessorNormalizationInfo normalizationInfo;
const DWORD spinCount = g_SpinConstants.dwMonitorSpinCount;
for (DWORD spinIteration = 0; spinIteration < spinCount; ++spinIteration)
{
AwareLock::SpinWait(spinCount);
AwareLock::SpinWait(normalizationInfo, spinIteration);

LONG oldValue = m_SyncBlockValue.LoadWithoutBarrier();

Expand All @@ -1945,15 +1945,15 @@ AwareLock::EnterHelperResult ObjHeader::EnterObjMonitorHelperSpin(Thread* pCurTh
return result;
}

spinCount *= backoffFactor;
if (spinCount <= maxSpinCount)
++spinIteration;
if (spinIteration < spinCount)
{
while (true)
{
AwareLock::SpinWait(spinCount);
AwareLock::SpinWait(normalizationInfo, spinIteration);

spinCount *= backoffFactor;
if (spinCount > maxSpinCount)
++spinIteration;
if (spinIteration >= spinCount)
{
// The last lock attempt for this spin will be done after the loop
break;
Expand Down Expand Up @@ -3188,38 +3188,22 @@ BOOL AwareLock::EnterEpilogHelper(Thread* pCurThread, INT32 timeOut)
// spin duration before it gets deprioritized behind all other waiters.
if (g_SystemInfo.dwNumberOfProcessors > 1)
{
DWORD maxSpinCount = g_SpinConstants.dwMaximumDuration;
DWORD spinCount = g_SpinConstants.dwInitialDuration;
if (spinCount <= maxSpinCount)
bool acquiredLock = false;
YieldProcessorNormalizationInfo normalizationInfo;
const DWORD spinCount = g_SpinConstants.dwMonitorSpinCount;
for (DWORD spinIteration = 0; spinIteration < spinCount; ++spinIteration)
{
if (m_lockState.InterlockedTry_LockAndUnregisterWaiterAndObserveWakeSignal())
{
acquiredLock = true;
break;
}

bool acquiredLock = false;
DWORD backoffFactor = g_SpinConstants.dwBackoffFactor;
while (true)
{
SpinWait(spinCount);

spinCount *= backoffFactor;
if (spinCount > maxSpinCount)
{
// The last lock attempt for this spin will be done after the loop
break;
}

if (m_lockState.InterlockedTry_LockAndUnregisterWaiterAndObserveWakeSignal())
{
acquiredLock = true;
break;
}
}
if (acquiredLock)
{
break;
}
SpinWait(normalizationInfo, spinIteration);
}
if (acquiredLock)
{
break;
}
}

Expand Down
12 changes: 7 additions & 5 deletions src/vm/syncblk.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "slist.h"
#include "crst.h"
#include "vars.hpp"
#include "yieldprocessornormalized.h"

// #SyncBlockOverview
//
Expand Down Expand Up @@ -165,6 +166,7 @@ inline void InitializeSpinConstants()
g_SpinConstants.dwMaximumDuration = min(g_pConfig->SpinLimitProcCap(), g_SystemInfo.dwNumberOfProcessors) * g_pConfig->SpinLimitProcFactor() + g_pConfig->SpinLimitConstant();
g_SpinConstants.dwBackoffFactor = g_pConfig->SpinBackoffFactor();
g_SpinConstants.dwRepetitions = g_pConfig->SpinRetryCount();
g_SpinConstants.dwMonitorSpinCount = g_SpinConstants.dwMaximumDuration == 0 ? 0 : g_pConfig->MonitorSpinCount();
#endif
}

Expand Down Expand Up @@ -205,11 +207,11 @@ class AwareLock
// Layout constants for m_state
static const UINT32 IsLockedMask = 0x1; // bit 0
static const UINT32 SpinnerCountIncrement = 0x2;
static const UINT32 SpinnerCountMask = 0x7e; // bits 1-6
static const UINT32 IsWaiterSignaledToWakeMask = 0x80; // bit 7
static const UINT32 WaiterCountShift = 8;
static const UINT32 SpinnerCountMask = 0xe; // bits 1-3
static const UINT32 IsWaiterSignaledToWakeMask = 0x10; // bit 4
static const UINT8 WaiterCountShift = 5;
static const UINT32 WaiterCountIncrement = (UINT32)1 << WaiterCountShift;
static const UINT32 WaiterCountMask = (UINT32)-1 >> WaiterCountShift << WaiterCountShift; // bits 8-31
static const UINT32 WaiterCountMask = (UINT32)-1 >> WaiterCountShift << WaiterCountShift; // bits 5-31

private:
UINT32 m_state;
Expand Down Expand Up @@ -484,7 +486,7 @@ class AwareLock
}

public:
static void SpinWait(DWORD spinCount);
static void SpinWait(const YieldProcessorNormalizationInfo &normalizationInfo, DWORD spinIteration);

// Helper encapsulating the fast path entering monitor. Returns what kind of result was achieved.
bool TryEnterHelper(Thread* pCurThread);
Expand Down
Loading

0 comments on commit c02b433

Please sign in to comment.