[+] 32bit SOO sizes for sync primitives under x86_32/MSVC

[*] Optimize the write-biased reentrant read-write lock down to 88 bytes on MSVC x64
This commit is contained in:
Reece Wilson 2023-06-17 17:08:58 +01:00
parent 451b9025c0
commit 2d6dca4e21
3 changed files with 95 additions and 64 deletions

View File

@ -14,41 +14,75 @@
namespace Aurora::Threading::Primitives
{
static const auto kDefaultPrimitiveSize = 128;
static const auto kDefaultPrimitiveSize64 = 128;
static const auto kPrimitiveSizeNTMutex = 16;
static const auto kPrimitiveSizeNTSemaphore = 64;
static const auto kPrimitiveSizeNTCS = 32;
static const auto kPrimitiveSizeNTEvent = 64;
static const auto kPrimitiveSizeNTRWLock = 104;
static const auto kPrimitiveSizeNTCond = 32;
static const auto kPrimitiveSizeNTCondMutex = 16;
static const auto kPrimitiveSize64NTMutex = 16;
static const auto kPrimitiveSize64NTSemaphore = 64;
static const auto kPrimitiveSize64NTCS = 32;
static const auto kPrimitiveSize64NTEvent = 64;
static const auto kPrimitiveSize64NTRWLock = 88;
static const auto kPrimitiveSize64NTCond = 32;
static const auto kPrimitiveSize64NTCondMutex = 16;
static const auto kPrimitiveSize32NTMutex = 8;
static const auto kPrimitiveSize32NTSemaphore = 36;
static const auto kPrimitiveSize32NTCS = 20;
static const auto kPrimitiveSize32NTEvent = 36;
static const auto kPrimitiveSize32NTRWLock = 56;
static const auto kPrimitiveSize32NTCond = 20;
static const auto kPrimitiveSize32NTCondMutex = 8;
#if defined(AURORA_IS_MODERNNT_DERIVED)
static const auto kPrimitiveSizeMutex = kPrimitiveSizeNTMutex;
static const auto kPrimitiveSizeSemaphore = kPrimitiveSizeNTSemaphore;
static const auto kPrimitiveSizeCS = kPrimitiveSizeNTCS;
static const auto kPrimitiveSizeEvent = kPrimitiveSizeNTEvent;
static const auto kPrimitiveSizeRWLock = kPrimitiveSizeNTRWLock;
static const auto kPrimitiveSizeCond = kPrimitiveSizeNTCond;
static const auto kPrimitiveSizeCondMutex = kPrimitiveSizeNTCondMutex;
// fuck you, its time to overtake the STL in even Windows 11 micro-benchmarks
#define AURT_ENABLE_HYPER_MUTEX
static const auto kPrimitiveSize64Mutex = kPrimitiveSize64NTMutex;
static const auto kPrimitiveSize64Semaphore = kPrimitiveSize64NTSemaphore;
static const auto kPrimitiveSize64CS = kPrimitiveSize64NTCS;
static const auto kPrimitiveSize64Event = kPrimitiveSize64NTEvent;
static const auto kPrimitiveSize64RWLock = kPrimitiveSize64NTRWLock;
static const auto kPrimitiveSize64Cond = kPrimitiveSize64NTCond;
static const auto kPrimitiveSize64CondMutex = kPrimitiveSize64NTCondMutex;
//#elif defined(AURORA_IS_LINUX_DERIVED)
//
static const auto kPrimitiveSize32Mutex = kPrimitiveSize32NTMutex;
static const auto kPrimitiveSize32Semaphore = kPrimitiveSize32NTSemaphore;
static const auto kPrimitiveSize32CS = kPrimitiveSize32NTCS;
static const auto kPrimitiveSize32Event = kPrimitiveSize32NTEvent;
static const auto kPrimitiveSize32RWLock = kPrimitiveSize32NTRWLock;
static const auto kPrimitiveSize32Cond = kPrimitiveSize32NTCond;
static const auto kPrimitiveSize32CondMutex = kPrimitiveSize32NTCondMutex;
#define AURT_ENABLE_HYPER_MUTEX
#else
static const auto kPrimitiveSizeMutex = kDefaultPrimitiveSize;
static const auto kPrimitiveSizeSemaphore = kDefaultPrimitiveSize;
static const auto kPrimitiveSizeCS = kDefaultPrimitiveSize;
static const auto kPrimitiveSizeEvent = kDefaultPrimitiveSize;
static const auto kPrimitiveSizeRWLock = kDefaultPrimitiveSize;
static const auto kPrimitiveSizeCond = kDefaultPrimitiveSize;
static const auto kPrimitiveSizeCondMutex = kDefaultPrimitiveSize;
static const auto kPrimitiveSize64Mutex = kDefaultPrimitiveSize64;
static const auto kPrimitiveSize64Semaphore = kDefaultPrimitiveSize64;
static const auto kPrimitiveSize64CS = kDefaultPrimitiveSize64;
static const auto kPrimitiveSize64Event = kDefaultPrimitiveSize64;
static const auto kPrimitiveSize64RWLock = kDefaultPrimitiveSize64;
static const auto kPrimitiveSize64Cond = kDefaultPrimitiveSize64;
static const auto kPrimitiveSize64CondMutex = kDefaultPrimitiveSize64;
#endif
#if defined(AURORA_IS_64BIT)
static const auto kPrimitiveSizeMutex = kPrimitiveSize64Mutex;
static const auto kPrimitiveSizeSemaphore = kPrimitiveSize64Semaphore;
static const auto kPrimitiveSizeCS = kPrimitiveSize64CS;
static const auto kPrimitiveSizeEvent = kPrimitiveSize64Event;
static const auto kPrimitiveSizeRWLock = kPrimitiveSize64RWLock;
static const auto kPrimitiveSizeCond = kPrimitiveSize64Cond;
static const auto kPrimitiveSizeCondMutex = kPrimitiveSize64CondMutex;
#else
static const auto kPrimitiveSizeMutex = kPrimitiveSize32Mutex;
static const auto kPrimitiveSizeSemaphore = kPrimitiveSize32Semaphore;
static const auto kPrimitiveSizeCS = kPrimitiveSize32CS;
static const auto kPrimitiveSizeEvent = kPrimitiveSize32Event;
static const auto kPrimitiveSizeRWLock = kPrimitiveSize32RWLock;
static const auto kPrimitiveSizeCond = kPrimitiveSize32Cond;
static const auto kPrimitiveSizeCondMutex = kPrimitiveSize32CondMutex;
#endif

View File

@ -6,21 +6,29 @@
Author: Reece
***/
#include <Source/RuntimeInternal.hpp>
//#define RWLOCK_VIEW_HAS_PARENT
#include "AuRWLock.hpp"
#include "SMTYield.hpp"
namespace Aurora::Threading::Primitives
{
#if defined(RWLOCK_VIEW_HAS_PARENT)
#define ViewParent (&this->parent_)
#else
#define ViewParent ((T *)(((char *)this) - (bIsReadView ? RWLockImpl<true>::kOffsetOfRead : RWLockImpl<true>::kOffsetOfWrite)))
#endif
template<bool bIsReadView, typename T>
void RWLockAccessView<bIsReadView, T>::Unlock()
{
if constexpr (bIsReadView)
{
this->parent_.UnlockRead();
ViewParent->UnlockRead();
}
else
{
this->parent_.UnlockWrite();
ViewParent->UnlockWrite();
}
}
@ -29,11 +37,11 @@ namespace Aurora::Threading::Primitives
{
if constexpr (bIsReadView)
{
return this->parent_.LockReadNS(AuMSToNS<AuUInt64>(timeout));
return ViewParent->LockReadNS(AuMSToNS<AuUInt64>(timeout));
}
else
{
return this->parent_.LockWriteNS(AuMSToNS<AuUInt64>(timeout));
return ViewParent->LockWriteNS(AuMSToNS<AuUInt64>(timeout));
}
}
@ -42,11 +50,11 @@ namespace Aurora::Threading::Primitives
{
if constexpr (bIsReadView)
{
return this->parent_.LockReadNS(timeout);
return ViewParent->LockReadNS(timeout);
}
else
{
return this->parent_.LockWriteNS(timeout);
return ViewParent->LockWriteNS(timeout);
}
}
@ -55,18 +63,20 @@ namespace Aurora::Threading::Primitives
{
if constexpr (bIsReadView)
{
return this->parent_.TryLockRead();
return ViewParent->TryLockRead();
}
else
{
return this->parent_.TryLockWrite();
return ViewParent->TryLockWrite();
}
}
template<bool bIsWriteRecursionAllowed>
RWLockImpl<bIsWriteRecursionAllowed>::RWLockImpl() :
read_(*this),
RWLockImpl<bIsWriteRecursionAllowed>::RWLockImpl()
#if defined(RWLOCK_VIEW_HAS_PARENT)
: read_(*this),
write_(*this)
#endif
#if 0
, condition_(AuUnsafeRaiiToShared(&this->mutex_)),
conditionWriter_(AuUnsafeRaiiToShared(&this->mutex_))
@ -80,13 +90,6 @@ namespace Aurora::Threading::Primitives
{
}
template<bool bIsWriteRecursionAllowed>
bool RWLockImpl<bIsWriteRecursionAllowed>::Init()
{
return true;
}
template<bool bIsWriteRecursionAllowed>
ConditionVariableImpl &RWLockImpl<bIsWriteRecursionAllowed>::GetCondition()
{
@ -220,9 +223,9 @@ namespace Aurora::Threading::Primitives
#if defined(AURWLOCK_NO_SIZE_OPTIMIZED_CONDVAR)
if (!this->GetConditionWriter().WaitForSignalNS(uSecondTimeout))
#else
#else
if (!this->GetConditionWriter().WaitForSignalNsEx(AuUnsafeRaiiToShared(&this->mutex_), uSecondTimeout))
#endif
#endif
{
this->writersPending_--;
return false;
@ -407,12 +410,6 @@ namespace Aurora::Threading::Primitives
return nullptr;
}
if (!pRwLock->Init())
{
delete pRwLock;
return nullptr;
}
return pRwLock;
}
@ -429,12 +426,6 @@ namespace Aurora::Threading::Primitives
return nullptr;
}
if (!pRwLock->Init())
{
delete pRwLock;
return nullptr;
}
return pRwLock;
}

View File

@ -19,10 +19,13 @@ namespace Aurora::Threading::Primitives
template<bool bIsReadView, typename T>
struct RWLockAccessView : IWaitable
{
RWLockAccessView(T &impl) : parent_(impl)
#if defined(RWLOCK_VIEW_HAS_PARENT)
RWLockAccessView(T &impl) :
parent_(impl)
{
}
#endif
bool LockMS(AuUInt64 timeout) override;
bool LockNS(AuUInt64 timeout) override;
@ -47,7 +50,9 @@ namespace Aurora::Threading::Primitives
void Unlock() override;
private:
#if defined(RWLOCK_VIEW_HAS_PARENT)
T &parent_;
#endif
};
template<bool bIsWriteRecursionAllowed>
@ -70,16 +75,11 @@ namespace Aurora::Threading::Primitives
IWaitable *AsReadable() override;
IWaitable *AsWritable() override;
bool Init();
auline ConditionVariableImpl &GetCondition();
auline ConditionVariableImpl &GetConditionWriter();
private:
//bool reentrantWriteLock_ {true};
ThreadCookie_t reentrantWriteLockHandle_ {};
RWLockAccessView<true, RWLockImpl> read_;
RWLockAccessView<false, RWLockImpl> write_;
@ -91,9 +91,15 @@ namespace Aurora::Threading::Primitives
char conditionVariable_[kSizeOfDummyCondVar] {};
char conditionVariableWriter_[kSizeOfDummyCondVar] {};
#endif
ThreadCookie_t reentrantWriteLockHandle_ {};
volatile AuInt32 state_ {};
AuInt32 writersPending_ : 31 {};
AuInt32 bElevaterPending_ : 1 {};
//bool bElevaterPending_{};
//bool reentrantWriteLock_ {true};
public:
cstatic const AuUInt8 kOffsetOfRead = AuOffsetOf(&RWLockImpl::read_);
cstatic const AuUInt8 kOffsetOfWrite = AuOffsetOf(&RWLockImpl::write_);
};
}