From 3681507136a60b46dbd9e2c70ccadb33ea1e9b25 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Sat, 7 Apr 2018 17:43:47 +0300 Subject: [PATCH] Rewrite vm::reservation Use flat virtual memory area --- rpcs3/Emu/Cell/SPUThread.cpp | 5 ++++ rpcs3/Emu/Memory/vm.cpp | 58 +++++++----------------------------- rpcs3/Emu/Memory/vm.h | 15 ++++++++-- 3 files changed, 27 insertions(+), 51 deletions(-) diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 0902f41edb..083122bd0a 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -314,6 +314,7 @@ std::string SPUThread::dump() const // Print some transaction statistics fmt::append(ret, "\nTX: %u; Fail: %u", tx_success, tx_failure); + fmt::append(ret, "\nRaddr: 0x%08x; R: 0x%x", raddr, raddr ? +vm::reservation_acquire(raddr, 128) : 0); fmt::append(ret, "\nTag Mask: 0x%08x", ch_tag_mask); fmt::append(ret, "\nMFC Stall: 0x%08x", ch_stall_mask); fmt::append(ret, "\nMFC Queue Size: %u", mfc_size); @@ -1174,6 +1175,9 @@ bool SPUThread::process_mfc_cmd(spu_mfc_cmd args) // Second transaction attempt vm::reader_lock lock; + // Touch reservation memory area as well + vm::reservation_acquire(raddr, 128) += 0; + if (utils::transaction_enter()) { if (rtime == vm::reservation_acquire(raddr, 128) && rdata == data) @@ -1183,6 +1187,7 @@ bool SPUThread::process_mfc_cmd(spu_mfc_cmd args) vm::reservation_update(raddr, 128); } + _xend(); tx_success++; diff --git a/rpcs3/Emu/Memory/vm.cpp b/rpcs3/Emu/Memory/vm.cpp index 13d95771f6..f0894d0e0d 100644 --- a/rpcs3/Emu/Memory/vm.cpp +++ b/rpcs3/Emu/Memory/vm.cpp @@ -36,12 +36,12 @@ namespace vm // Stats for debugging u8* const g_stat_addr = memory_reserve_4GiB((std::uintptr_t)g_exec_addr); + // Reservation stats (compressed x16) + u8* const g_reservations = memory_reserve_4GiB((std::uintptr_t)g_stat_addr); + // Memory locations std::vector> g_locations; - // Reservations (lock lines) in a single memory page - using reservation_info = std::array, 4096 / 128>; - // Registered waiters std::deque g_waiters; @@ -235,48 +235,11 @@ namespace vm { // Memory flags atomic_t flags; - - atomic_t waiters; - - // Reservations - atomic_t reservations; - - // Access reservation info - std::atomic& operator [](u32 addr) - { - auto ptr = reservations.load(); - - if (!ptr) - { - // Opportunistic memory allocation - ptr = new reservation_info{}; - - if (auto old_ptr = reservations.compare_and_swap(nullptr, ptr)) - { - delete ptr; - ptr = old_ptr; - } - } - - return (*ptr)[(addr & 0xfff) >> 7]; - } }; // Memory pages std::array g_pages{}; - u64 reservation_acquire(u32 addr, u32 _size) - { - // Access reservation info: stamp and the lock bit - return g_pages[addr >> 12][addr].load(std::memory_order_acquire); - } - - void reservation_update(u32 addr, u32 _size, bool lsb) - { - // Update reservation info with new timestamp (unsafe, assume allocated) - (*g_pages[addr >> 12].reservations)[(addr & 0xfff) >> 7].store((__rdtsc() & -2) | lsb, std::memory_order_release); - } - void waiter::init() { // Register waiter @@ -292,14 +255,7 @@ namespace vm return; } - memory_page& page = g_pages[addr >> 12]; - - if (page.reservations == nullptr) - { - return; - } - - if (stamp >= (*page.reservations)[(addr & 0xfff) >> 7].load()) + if (stamp >= reservation_acquire(addr, size)) { return; } @@ -563,6 +519,11 @@ namespace vm , size(size) , flags(flags) { + // Allocate compressed reservation info area (avoid RSX and SPU areas) + if (addr != 0xc0000000 && addr != 0xe0000000) + { + utils::memory_commit(g_reservations + addr / 16, size / 16); + } } block_t::~block_t() @@ -826,6 +787,7 @@ namespace vm utils::memory_decommit(g_base_addr, 0x100000000); utils::memory_decommit(g_exec_addr, 0x100000000); utils::memory_decommit(g_stat_addr, 0x100000000); + utils::memory_decommit(g_reservations, 0x100000000); } } diff --git a/rpcs3/Emu/Memory/vm.h b/rpcs3/Emu/Memory/vm.h index 574c97d5be..34d4a36d39 100644 --- a/rpcs3/Emu/Memory/vm.h +++ b/rpcs3/Emu/Memory/vm.h @@ -13,6 +13,7 @@ namespace vm extern u8* const g_base_addr; extern u8* const g_exec_addr; extern u8* const g_stat_addr; + extern u8* const g_reservations; enum memory_location_t : uint { @@ -100,10 +101,18 @@ namespace vm }; // Get reservation status for further atomic update: last update timestamp - u64 reservation_acquire(u32 addr, u32 size); + inline atomic_t& reservation_acquire(u32 addr, u32 size) + { + // Access reservation info: stamp and the lock bit + return reinterpret_cast*>(g_reservations)[addr / 128]; + } - // End atomic update - void reservation_update(u32 addr, u32 size, bool lsb = false); + // Update reservation status + inline void reservation_update(u32 addr, u32 size, bool lsb = false) + { + // Update reservation info with new timestamp + reservation_acquire(addr, size) = (__rdtsc() & -2) | lsb; + } // Check and notify memory changes at address void notify(u32 addr, u32 size);