mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-03-13 07:14:49 +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
@ -2168,28 +2168,28 @@ void spu_thread::do_dma_transfer(spu_thread* _this, const spu_mfc_cmd& args, u8*
|
||||
{
|
||||
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);
|
||||
range_lock->release(0);
|
||||
break;
|
||||
}
|
||||
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);
|
||||
range_lock->release(0);
|
||||
break;
|
||||
}
|
||||
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);
|
||||
range_lock->release(0);
|
||||
break;
|
||||
}
|
||||
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);
|
||||
range_lock->release(0);
|
||||
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)
|
||||
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);
|
||||
return !res;
|
||||
|
@ -42,7 +42,7 @@ namespace vm
|
||||
void range_lock_internal(atomic_t<u64, 64>* range_lock, u32 begin, u32 size);
|
||||
|
||||
// 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)
|
||||
{
|
||||
const u32 size = Size ? Size : _size;
|
||||
@ -63,7 +63,7 @@ namespace vm
|
||||
{
|
||||
lock_size = 128;
|
||||
|
||||
if (TouchMem && is_share) [[unlikely]]
|
||||
if (is_share) [[unlikely]]
|
||||
{
|
||||
addr = static_cast<u16>(begin) | is_share;
|
||||
lock_addr = lock_val;
|
||||
@ -80,30 +80,10 @@ namespace vm
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
range_lock->release(0);
|
||||
|
||||
if constexpr (!TouchMem)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr (!TouchMem)
|
||||
{
|
||||
// Give up
|
||||
range_lock->release(0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Fallback to slow path
|
||||
|
Loading…
x
Reference in New Issue
Block a user