From 74dc6772b0c5b4537b82a4b2395e6f6074d73589 Mon Sep 17 00:00:00 2001 From: Jamie Reece Wilson Date: Sun, 10 Sep 2023 14:50:59 +0100 Subject: [PATCH] [+] Non-mutually exclusive binary semaphore / event wait path [+] ThreadingConfig::gPreferFutexEvent --- Include/Aurora/Runtime.hpp | 3 +- Source/Threading/Primitives/AuEvent.cpp | 99 ++++++++++++++++-------- Source/Threading/Primitives/AuEvent.hpp | 2 + Source/Threading/Primitives/SMTYield.cpp | 7 +- Source/Threading/Primitives/SMTYield.hpp | 2 + 5 files changed, 78 insertions(+), 35 deletions(-) diff --git a/Include/Aurora/Runtime.hpp b/Include/Aurora/Runtime.hpp index 50e4a7f7..e6db916e 100644 --- a/Include/Aurora/Runtime.hpp +++ b/Include/Aurora/Runtime.hpp @@ -379,11 +379,12 @@ namespace Aurora AuUInt64 uAdaptiveSpinCUCnt8 : 4 { 2 }; AuUInt64 uAdaptiveSpinCUCnt16 : 4 { 4 }; AuUInt64 bPreferFutexRWLock : 1 { true }; - AuUInt64 bWinXpThrough7BlazeOptimizerPower : 7 { 6 }; // dont worry about it. we dont care about old portables. lets try to make older win32 targets tweak the scheduling in our favor a bit. + AuUInt64 bWinXpThrough7BlazeOptimizerPower : 12 { 300 }; // dont worry about it. we dont care about old portables. lets try to make older win32 targets tweak the scheduling in our favor a bit. AuUInt64 bPreferLinuxPrimitivesFutexNoSpin : 1 { false }; AuUInt64 bPreferUnixPrimitivesNoSpin : 1 { false }; AuUInt64 bAlwaysRWLockWriteBiasOnReadLock : 1 { false }; AuUInt64 bEnableRWLockWriteBiasOnReadLock : 1 { true }; + AuUInt64 bPreferFutexEvent : 1 { true }; }; struct DummyConfig diff --git a/Source/Threading/Primitives/AuEvent.cpp b/Source/Threading/Primitives/AuEvent.cpp index 181531af..10960423 100644 --- a/Source/Threading/Primitives/AuEvent.cpp +++ b/Source/Threading/Primitives/AuEvent.cpp @@ -8,6 +8,7 @@ #include #include "AuEvent.hpp" #include "SMTYield.hpp" +#include "../AuWakeInternal.hpp" namespace Aurora::Threading::Primitives { @@ -44,27 +45,50 @@ namespace Aurora::Threading::Primitives uStartTime = Time::SteadyClockNS(); uEndTime = uStartTime + uTimeout; } - - AU_LOCK_GUARD(this->mutex_); - while (!AtomicIsEventSetLogicNoSpinNoLock()) + if (gPreferFutexEvent) { - AuUInt32 uTimeoutNS {}; - - if (uTimeout) + while (!AtomicIsEventSetLogicNoSpinNoLock()) { - uStartTime = Time::SteadyClockNS(); - if (uStartTime >= uEndTime) + EventBits bits; + bits.state = AuAtomicLoad(&this->state_); + + if (bits.bTriggered) { - return false; + if (!InternalLTSWaitOnAddressHighRes(&this->state_, &bits.state, sizeof(bits.state), uEndTime)) + { + return false; + } + } + else + { + SMPPause(); + } + } + } + else + { + AU_LOCK_GUARD(this->mutex_); + + while (!AtomicIsEventSetLogicNoSpinNoLock()) + { + AuUInt32 uTimeoutNS {}; + + if (uTimeout) + { + uStartTime = Time::SteadyClockNS(); + if (uStartTime >= uEndTime) + { + return false; + } + + uTimeoutNS = uEndTime - uStartTime; } - uTimeoutNS = uEndTime - uStartTime; - } - - if (!this->condition_.WaitForSignalNsEx(&this->mutex_, uTimeoutNS)) - { - continue; + if (!this->condition_.WaitForSignalNsEx(&this->mutex_, uTimeoutNS)) + { + continue; + } } } @@ -139,17 +163,7 @@ namespace Aurora::Threading::Primitives } } - this->mutex_.Lock(); - this->mutex_.Unlock(); - - if (bits.bAtomicRelease) - { - this->condition_.Signal(); - } - else - { - this->condition_.Broadcast(); - } + this->DoSignal(bits); } bool EventImpl::TrySet() @@ -176,19 +190,38 @@ namespace Aurora::Threading::Primitives } } - this->mutex_.Lock(); - this->mutex_.Unlock(); + this->DoSignal(bits); - if (bits.bAtomicRelease) + return true; + } + + void EventImpl::DoSignal(const EventBits &bits) + { + if (gPreferFutexEvent) { - this->condition_.Signal(); + if (bits.bAtomicRelease) + { + InternalLTSWakeOne(&this->state_); + } + else + { + InternalLTSWakeAll(&this->state_); + } } else { - this->condition_.Broadcast(); - } + this->mutex_.Lock(); + this->mutex_.Unlock(); - return true; + if (bits.bAtomicRelease) + { + this->condition_.Signal(); + } + else + { + this->condition_.Broadcast(); + } + } } bool EventImpl::HasOSHandle(AuMach &mach) diff --git a/Source/Threading/Primitives/AuEvent.hpp b/Source/Threading/Primitives/AuEvent.hpp index f8ebcbeb..b3424fbf 100644 --- a/Source/Threading/Primitives/AuEvent.hpp +++ b/Source/Threading/Primitives/AuEvent.hpp @@ -64,6 +64,8 @@ namespace Aurora::Threading::Primitives AuUInt8 state_; }; + + void DoSignal(const EventBits &bits); #endif }; } \ No newline at end of file diff --git a/Source/Threading/Primitives/SMTYield.cpp b/Source/Threading/Primitives/SMTYield.cpp index 79422850..32ee3adc 100644 --- a/Source/Threading/Primitives/SMTYield.cpp +++ b/Source/Threading/Primitives/SMTYield.cpp @@ -78,8 +78,12 @@ namespace Aurora::Threading::Primitives { auto uCores = AuHwInfo::GetCPUInfo().uThreads; + bool bPermitWOAInternal = IsWaitOnRecommended(); gUseFutexRWLock = ThrdCfg::gPreferFutexRWLock && - IsWaitOnRecommended(); + bPermitWOAInternal; + + gPreferFutexEvent = ThrdCfg::gPreferFutexEvent && + bPermitWOAInternal; gSpinAdaptiveThreadCount = uCores; @@ -176,5 +180,6 @@ namespace Aurora::Threading::Primitives ThrdCfg::gPreferUnixPrimitivesNoSpin = gRuntimeConfig.threadingConfig.bPreferUnixPrimitivesNoSpin; ThrdCfg::gAlwaysRWLockWriteBiasOnReadLock = gRuntimeConfig.threadingConfig.bAlwaysRWLockWriteBiasOnReadLock; ThrdCfg::gEnableRWLockWriteBiasOnReadLock = gRuntimeConfig.threadingConfig.bEnableRWLockWriteBiasOnReadLock; + ThrdCfg::gPreferFutexEvent = gRuntimeConfig.threadingConfig.bPreferFutexEvent; } } \ No newline at end of file diff --git a/Source/Threading/Primitives/SMTYield.hpp b/Source/Threading/Primitives/SMTYield.hpp index 19b990b0..188bf0bc 100644 --- a/Source/Threading/Primitives/SMTYield.hpp +++ b/Source/Threading/Primitives/SMTYield.hpp @@ -45,6 +45,7 @@ namespace Aurora::Threading::Primitives inline AuUInt32 gAdaptiveSpinCUCnt8 {}; inline AuUInt32 gAdaptiveSpinCUCnt16 {}; inline bool gPreferFutexRWLock {}; + inline bool gPreferFutexEvent {}; inline bool gWinXpThrough7BlazeOptimizerPower {}; inline bool gPreferLinuxPrimitivesFutexNoSpin {}; inline bool gPreferUnixPrimitivesNoSpin {}; @@ -57,6 +58,7 @@ namespace Aurora::Threading::Primitives inline AuUInt32 gSpinAdaptiveThreadCount {}; inline AuUInt32 gUseFutexRWLock {}; + inline AuUInt32 gPreferFutexEvent {}; void InitAdaptiveThreshold(); void InitAdaptiveThresholdFirstTime();