mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-03-13 16:18:56 +00:00
SPU: improve spu_thread::reservation_check
Use optimistic locking and optimistic loop (expecting 1 iteration).
This commit is contained in:
parent
21ec32b465
commit
3507cd0a37
rpcs3/Emu
@ -2168,28 +2168,28 @@ void spu_thread::do_dma_transfer(spu_thread* _this, const spu_mfc_cmd& args, u8*
|
|||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
{
|
{
|
||||||
vm::range_lock<true, 1>(range_lock, eal, 1);
|
vm::range_lock<1>(range_lock, eal, 1);
|
||||||
*reinterpret_cast<u8*>(dst) = *reinterpret_cast<const u8*>(src);
|
*reinterpret_cast<u8*>(dst) = *reinterpret_cast<const u8*>(src);
|
||||||
range_lock->release(0);
|
range_lock->release(0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 2:
|
case 2:
|
||||||
{
|
{
|
||||||
vm::range_lock<true, 2>(range_lock, eal, 2);
|
vm::range_lock<2>(range_lock, eal, 2);
|
||||||
*reinterpret_cast<u16*>(dst) = *reinterpret_cast<const u16*>(src);
|
*reinterpret_cast<u16*>(dst) = *reinterpret_cast<const u16*>(src);
|
||||||
range_lock->release(0);
|
range_lock->release(0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 4:
|
case 4:
|
||||||
{
|
{
|
||||||
vm::range_lock<true, 4>(range_lock, eal, 4);
|
vm::range_lock<4>(range_lock, eal, 4);
|
||||||
*reinterpret_cast<u32*>(dst) = *reinterpret_cast<const u32*>(src);
|
*reinterpret_cast<u32*>(dst) = *reinterpret_cast<const u32*>(src);
|
||||||
range_lock->release(0);
|
range_lock->release(0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 8:
|
case 8:
|
||||||
{
|
{
|
||||||
vm::range_lock<true, 8>(range_lock, eal, 8);
|
vm::range_lock<8>(range_lock, eal, 8);
|
||||||
*reinterpret_cast<u64*>(dst) = *reinterpret_cast<const u64*>(src);
|
*reinterpret_cast<u64*>(dst) = *reinterpret_cast<const u64*>(src);
|
||||||
range_lock->release(0);
|
range_lock->release(0);
|
||||||
break;
|
break;
|
||||||
@ -3223,9 +3223,73 @@ bool spu_thread::reservation_check(u32 addr, const decltype(rdata)& data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Ensure data is allocated (HACK: would raise LR event if not)
|
// Ensure data is allocated (HACK: would raise LR event if not)
|
||||||
vm::range_lock<false>(range_lock, addr, 128);
|
// Set range_lock first optimistically
|
||||||
|
range_lock->store(u64{128} << 32 | addr);
|
||||||
|
|
||||||
const bool res = *range_lock && cmp_rdata(data, vm::_ref<decltype(rdata)>(addr));
|
u64 lock_val = vm::g_range_lock;
|
||||||
|
u64 old_lock = 0;
|
||||||
|
|
||||||
|
while (lock_val != old_lock)
|
||||||
|
{
|
||||||
|
// Since we want to read data, let's check readability first
|
||||||
|
if (!(lock_val & vm::range_readable))
|
||||||
|
{
|
||||||
|
// Only one abnormal operation is "unreadable"
|
||||||
|
if ((lock_val >> vm::range_pos) == (vm::range_locked >> vm::range_pos))
|
||||||
|
{
|
||||||
|
// All page flags are untouched and can be read safely
|
||||||
|
if (!vm::check_addr(addr, 128))
|
||||||
|
{
|
||||||
|
// Assume our memory is being (de)allocated
|
||||||
|
range_lock->release(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// g_shmem values are unchanged too
|
||||||
|
const u64 is_shmem = vm::g_shmem[addr >> 16];
|
||||||
|
|
||||||
|
const u64 test_addr = is_shmem ? (is_shmem | static_cast<u16>(addr)) / 128 : u64{addr} / 128;
|
||||||
|
const u64 lock_addr = lock_val / 128;
|
||||||
|
|
||||||
|
if (test_addr == lock_addr)
|
||||||
|
{
|
||||||
|
// Our reservation is locked
|
||||||
|
range_lock->release(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback to normal range check
|
||||||
|
const u64 lock_addr = static_cast<u32>(lock_val);
|
||||||
|
const u32 lock_size = static_cast<u32>(lock_val << 3 >> 35);
|
||||||
|
|
||||||
|
if (lock_addr + lock_size <= addr || lock_addr >= addr + 128)
|
||||||
|
{
|
||||||
|
// We are outside locked range, so page flags are unaffected
|
||||||
|
if (!vm::check_addr(addr, 128))
|
||||||
|
{
|
||||||
|
range_lock->release(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!(lock_val & vm::range_readable))
|
||||||
|
{
|
||||||
|
range_lock->release(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
old_lock = std::exchange(lock_val, vm::g_range_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!range_lock->load()) [[unlikely]]
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool res = cmp_rdata(data, vm::_ref<decltype(rdata)>(addr));
|
||||||
|
|
||||||
range_lock->release(0);
|
range_lock->release(0);
|
||||||
return !res;
|
return !res;
|
||||||
|
@ -42,7 +42,7 @@ namespace vm
|
|||||||
void range_lock_internal(atomic_t<u64, 64>* range_lock, u32 begin, u32 size);
|
void range_lock_internal(atomic_t<u64, 64>* range_lock, u32 begin, u32 size);
|
||||||
|
|
||||||
// Lock memory range
|
// Lock memory range
|
||||||
template <bool TouchMem = true, uint Size = 0>
|
template <uint Size = 0>
|
||||||
FORCE_INLINE void range_lock(atomic_t<u64, 64>* range_lock, u32 begin, u32 _size)
|
FORCE_INLINE void range_lock(atomic_t<u64, 64>* range_lock, u32 begin, u32 _size)
|
||||||
{
|
{
|
||||||
const u32 size = Size ? Size : _size;
|
const u32 size = Size ? Size : _size;
|
||||||
@ -63,7 +63,7 @@ namespace vm
|
|||||||
{
|
{
|
||||||
lock_size = 128;
|
lock_size = 128;
|
||||||
|
|
||||||
if (TouchMem && is_share) [[unlikely]]
|
if (is_share) [[unlikely]]
|
||||||
{
|
{
|
||||||
addr = static_cast<u16>(begin) | is_share;
|
addr = static_cast<u16>(begin) | is_share;
|
||||||
lock_addr = lock_val;
|
lock_addr = lock_val;
|
||||||
@ -80,30 +80,10 @@ namespace vm
|
|||||||
|
|
||||||
if (!new_lock_val || new_lock_val == lock_val) [[likely]]
|
if (!new_lock_val || new_lock_val == lock_val) [[likely]]
|
||||||
{
|
{
|
||||||
if constexpr (!TouchMem)
|
|
||||||
{
|
|
||||||
if (!vm::check_addr(begin, size, vm::page_writable))
|
|
||||||
{
|
|
||||||
range_lock->release(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
range_lock->release(0);
|
range_lock->release(0);
|
||||||
|
|
||||||
if constexpr (!TouchMem)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if constexpr (!TouchMem)
|
|
||||||
{
|
|
||||||
// Give up
|
|
||||||
range_lock->release(0);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback to slow path
|
// Fallback to slow path
|
||||||
|
Loading…
x
Reference in New Issue
Block a user