MTVU: port write pointer to atomic and optimize atomic access

Write pointer can be relaxed-read from the EE thread
Read pointer can be relaxed-read from the VU thread

Warning: AtomicExchange calls were replaced by release-store
However AtomicExchange generates a memory barrier (at least on linux)
So either it is useless and it will be faster, or it will explode ;)
This commit is contained in:
Gregory Hainaut 2016-07-03 10:54:12 +02:00
parent ca46921796
commit 3f0655c821
2 changed files with 18 additions and 18 deletions

View File

@ -75,11 +75,11 @@ void VU_Thread::Reset()
{
ScopedLock lock(mtxBusy);
write_pos = 0;
write_offset = 0;
vuCycleIdx = 0;
read_pos = 0;
isBusy = false;
write_pos = 0;
memzero(vif);
memzero(vifRegs);
memzero(vuCycles);
@ -97,7 +97,7 @@ void VU_Thread::ExecuteRingBuffer()
for(;;) {
semaEvent.WaitWithoutYield();
ScopedLockBool lock(mtxBusy, isBusy);
while (read_pos != GetWritePos()) {
while (read_pos.load(std::memory_order_relaxed) != GetWritePos()) {
u32 tag = Read();
switch (tag) {
case MTVU_VU_EXECUTE: {
@ -137,12 +137,12 @@ void VU_Thread::ExecuteRingBuffer()
Read(&vif.tag, vif_copy_size);
ReadRegs(&vifRegs);
u32 size = Read();
MTVU_Unpack(&buffer[read_pos], vifRegs);
MTVU_Unpack(&buffer[read_pos.load(std::memory_order_relaxed)], vifRegs);
incReadPos(size_u32(size));
break;
}
case MTVU_NULL_PACKET:
read_pos = 0;
read_pos.store(0, std::memory_order_release);
break;
jNO_DEFAULT;
}
@ -156,8 +156,8 @@ __ri void VU_Thread::WaitOnSize(s32 size)
{
for(;;) {
s32 readPos = GetReadPos();
if (readPos <= write_pos) break; // MTVU is reading in back of write_pos
if (readPos > write_pos + size) break; // Enough free front space
if (readPos <= write_pos.load(std::memory_order_relaxed)) break; // MTVU is reading in back of write_pos
if (readPos > write_pos.load(std::memory_order_relaxed) + size) break; // Enough free front space
if (1) { // Let MTVU run to free up buffer space
KickStart();
if (IsDevBuild) DevCon.WriteLn("WaitOnSize()");
@ -174,12 +174,12 @@ void VU_Thread::ReserveSpace(s32 size)
pxAssert(size < buffer_size);
pxAssert(size > 0);
pxAssert(write_offset == 0);
if (write_pos + size > buffer_size) {
if (write_pos.load(std::memory_order_relaxed) + size > buffer_size) {
pxAssert(write_pos > 0);
WaitOnSize(1); // Size of MTVU_NULL_PACKET
Write(MTVU_NULL_PACKET);
write_offset = 0;
AtomicExchange(volatize(write_pos), 0);
write_pos.store(0, std::memory_order_release);
}
WaitOnSize(size);
}
@ -187,17 +187,17 @@ void VU_Thread::ReserveSpace(s32 size)
// Use this when reading read_pos from ee thread
__fi s32 VU_Thread::GetReadPos()
{
return read_pos.load();
return read_pos.load(std::memory_order_acquire);
}
// Use this when reading write_pos from vu thread
__fi s32 VU_Thread::GetWritePos()
{
return AtomicRead(volatize(write_pos));
return write_pos.load(std::memory_order_acquire);
}
// Gets the effective write pointer after adding write_offset
__fi u32* VU_Thread::GetWritePtr()
{
return &buffer[(write_pos + write_offset) & buffer_mask];
return &buffer[(write_pos.load(std::memory_order_relaxed) + write_offset) & buffer_mask];
}
__fi void VU_Thread::incReadPos(s32 offset)
@ -206,29 +206,29 @@ __fi void VU_Thread::incReadPos(s32 offset)
}
__fi void VU_Thread::incWritePos()
{ // Adds write_offset
s32 temp = (write_pos + write_offset) & buffer_mask;
s32 temp = (write_pos.load(std::memory_order_relaxed) + write_offset) & buffer_mask;
write_offset = 0;
AtomicExchange(volatize(write_pos), temp);
write_pos.store(temp, std::memory_order_release);
if (MTVU_ALWAYS_KICK) KickStart();
if (MTVU_SYNC_MODE) WaitVU();
}
__fi u32 VU_Thread::Read()
{
u32 ret = buffer[read_pos];
u32 ret = buffer[read_pos.load(std::memory_order_relaxed)];
incReadPos(1);
return ret;
}
__fi void VU_Thread::Read(void* dest, u32 size)
{
memcpy(dest, &buffer[read_pos], size);
memcpy(dest, &buffer[read_pos.load(std::memory_order_relaxed)], size);
incReadPos(size_u32(size));
}
__fi void VU_Thread::ReadRegs(VIFregisters* dest)
{
VIFregistersMTVU* src = (VIFregistersMTVU*)&buffer[read_pos];
VIFregistersMTVU* src = (VIFregistersMTVU*)&buffer[read_pos.load(std::memory_order_relaxed)];
dest->cycle = src->cycle;
dest->mode = src->mode;
dest->num = src->num;
@ -272,7 +272,7 @@ u32 VU_Thread::Get_vuCycles()
void VU_Thread::KickStart(bool forceKick)
{
if ((forceKick && !semaEvent.Count())
|| (!isBusy.load(std::memory_order_relaxed) && GetReadPos() != write_pos)) semaEvent.Post();
|| (!isBusy.load(std::memory_order_relaxed) && GetReadPos() != write_pos.load(std::memory_order_relaxed))) semaEvent.Post();
}
bool VU_Thread::IsDone()

View File

@ -32,7 +32,7 @@ class VU_Thread : public pxThread {
__aligned(4) u32 buffer[buffer_size];
std::atomic<int> read_pos; // Only modified by VU thread
std::atomic<bool> isBusy; // Is thread processing data?
__aligned(4) s32 write_pos; // Only modified by EE thread
std::atomic<int> write_pos; // Only modified by EE thread
__aligned(4) s32 write_offset; // Only modified by EE thread
__aligned(4) Mutex mtxBusy;
__aligned(4) Semaphore semaEvent;