[+] More threading options

[+] AuThreading::SetSpinCountTimeout
[+] AuThreading::SetThreadLocalAdditionalSpinCountTimeout
This commit is contained in:
Reece Wilson 2023-08-19 18:14:28 +01:00
parent e6bf022bef
commit 8bf6bdd963
11 changed files with 116 additions and 9 deletions

View File

@ -338,6 +338,12 @@ namespace Aurora
bool bPreferNt51XpCondvarsOver8 { false };
bool bPreferNtCondvarModernWinSpin { false };
bool bPreferNtCondvarOlderWinSpin { true };
bool bPreferNtSemaphoreSpinTryLock { true };
bool bPreferNtMutexSpinTryLock { true };
bool bPreferNtCondMutexSpinTryLock { true };
bool bPreferLinuxSemaphoreSpinTryLock { true };
bool bPreferLinuxMutexSpinTryLock { true };
bool bPreferLinuxCondMutexSpinTryLock { true };
bool bPreferEmulatedWakeOnAddress { false };
};

View File

@ -0,0 +1,17 @@
/***
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: SpinTime.hpp
Date: 2023-08-19
Author: Reece
***/
#pragma once
namespace Aurora::Threading
{
// Note: the following APIs are in powers of 2!
AUKN_SYM void SetSpinCountTimeout(AuUInt8 uTimeout);
AUKN_SYM AuUInt8 GetSpinCountTimeout();
AUKN_SYM void SetThreadLocalAdditionalSpinCountTimeout(AuUInt8 uTimeout);
}

View File

@ -24,4 +24,6 @@ namespace Aurora::Threading
#include "LockGuard.hpp"
#include "LockGuardTry.hpp"
#include "SpinTime.hpp"
#include "Threads/Threads.hpp"

View File

@ -46,11 +46,23 @@ namespace Aurora::Threading::Primitives
#if defined(AURORA_FORCE_SRW_LOCKS)
return ::TryAcquireSRWLockExclusive(&this->lock_);
#else
if (gRuntimeConfig.threadingConfig.bPreferNtCondMutexSpinTryLock)
{
return TryLockHeavy();
}
else
{
return TryLockNoSpin();
}
#endif
}
bool Win32ConditionMutex::TryLockHeavy()
{
return DoTryIf([=]()
{
return this->TryLockNoSpin();
return TryLockNoSpin();
});
#endif
}
bool Win32ConditionMutex::TryLockNoSpin()
@ -68,7 +80,7 @@ namespace Aurora::Threading::Primitives
::AcquireSRWLockExclusive(&this->lock_);
#else
if (this->TryLock())
if (this->TryLockHeavy())
{
return;
}

View File

@ -41,6 +41,7 @@ namespace Aurora::Threading::Primitives
AuUInt GetOSHandle() override;
auline bool TryLockNoSpin();
auline bool TryLockHeavy();
#if !defined(AURORA_FORCE_SRW_LOCKS)
NT4Mutex lock_;

View File

@ -44,7 +44,7 @@ namespace Aurora::Threading::Primitives
return false;
}
bool MutexImpl::TryLock()
bool MutexImpl::TryLockHeavy()
{
return DoTryIf([=]()
{
@ -52,6 +52,18 @@ namespace Aurora::Threading::Primitives
});
}
bool MutexImpl::TryLock()
{
if (gRuntimeConfig.threadingConfig.bPreferNtMutexSpinTryLock)
{
return TryLockHeavy();
}
else
{
return TryLockNoSpin();
}
}
bool MutexImpl::TryLockNoSpin()
{
return AuAtomicTestAndSet(&this->state_, 0) == 0;
@ -82,7 +94,7 @@ namespace Aurora::Threading::Primitives
{
bool returnValue = false;
if (this->TryLock())
if (this->TryLockHeavy())
{
return true;
}

View File

@ -22,7 +22,8 @@ namespace Aurora::Threading::Primitives
bool LockNS(AuUInt64 timeout) override;
void Unlock() override;
auline bool TryLockNoSpin();
auline bool TryLockNoSpin();
auline bool TryLockHeavy();
private:
#if defined(AURORA_FORCE_SRW_LOCKS)

View File

@ -35,20 +35,32 @@ namespace Aurora::Threading::Primitives
{
return true;
}
bool SemaphoreImpl::TryLockNoSpin()
{
auto old = this->dwState_;
return (old != 0 && AuAtomicCompareExchange(&this->dwState_, old - 1, old) == old);
}
bool SemaphoreImpl::TryLock()
bool SemaphoreImpl::TryLockHeavy()
{
return DoTryIf([=]()
{
return TryLockNoSpin();
});
}
bool SemaphoreImpl::TryLock()
{
if (gRuntimeConfig.threadingConfig.bPreferNtSemaphoreSpinTryLock)
{
return TryLockHeavy();
}
else
{
return TryLockNoSpin();
}
}
bool SemaphoreImpl::LockMS(AuUInt64 uTimeout)
{
@ -57,7 +69,7 @@ namespace Aurora::Threading::Primitives
bool SemaphoreImpl::LockNS(AuUInt64 uTimeout)
{
if (this->TryLock())
if (this->TryLockHeavy())
{
return true;
}

View File

@ -27,6 +27,7 @@ namespace Aurora::Threading::Primitives
void Unlock() override;
auline bool TryLockNoSpin();
auline bool TryLockHeavy();
private:
AuUInt32 dwState_ {};

View File

@ -8,6 +8,25 @@
#include <Source/RuntimeInternal.hpp>
#include "SMTYield.hpp"
namespace Aurora::Threading
{
AUKN_SYM void SetSpinCountTimeout(AuUInt8 uTimeout)
{
gRuntimeConfig.threadingConfig.uSpinLoopPowerA = uTimeout;
}
AUKN_SYM AuUInt8 GetSpinCountTimeout()
{
return gRuntimeConfig.threadingConfig.uSpinLoopPowerA;
}
AUKN_SYM void SetThreadLocalAdditionalSpinCountTimeout(AuUInt8 uTimeout)
{
gHasThreadLocalTimeout = 1;
tlSpinCountLocal = uTimeout;
}
}
namespace Aurora::Threading::Primitives
{

View File

@ -7,6 +7,12 @@
***/
#pragma once
namespace Aurora::Threading
{
inline AuUInt32 gHasThreadLocalTimeout {};
inline thread_local AuUInt8 tlSpinCountLocal { 6 };
}
namespace Aurora::Threading::Primitives
{
static auline void SMPPause()
@ -46,6 +52,24 @@ namespace Aurora::Threading::Primitives
}
}
if (gHasThreadLocalTimeout)
{
auto uCount = tlSpinCountLocal;
int loops = (1 << uCount);
while (loops > 0)
{
SMPPause();
loops -= 1;
if (callback())
{
return true;
}
}
}
return callback();
}