Add PPU instruction stat dumper

Needs PPU Debug option to activate and PPU Interpreter
Dumps after Resume (after Pause)
Fix utils::memory_decommit, clean vm.cpp
This commit is contained in:
Nekotekina 2017-10-06 00:24:50 +03:00
parent f5d450f24c
commit df2fc13b7a
5 changed files with 61 additions and 43 deletions

View File

@ -70,7 +70,7 @@ namespace utils
void memory_decommit(void* pointer, std::size_t size)
{
#ifdef _WIN32
verify(HERE), ::VirtualFree(pointer, 0, MEM_DECOMMIT);
verify(HERE), ::VirtualFree(pointer, size, MEM_DECOMMIT);
#else
verify(HERE), ::mmap(pointer, size, PROT_NONE, MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
#endif

View File

@ -14,6 +14,11 @@ inline void ppu_cr_set(ppu_thread& ppu, u32 field, bool le, bool gt, bool eq, bo
ppu.cr[field * 4 + 1] = gt;
ppu.cr[field * 4 + 2] = eq;
ppu.cr[field * 4 + 3] = so;
if (UNLIKELY(g_cfg.core.ppu_debug))
{
*(u32*)(vm::g_stat_addr + ppu.cia) |= *(u32*)(u8*)(ppu.cr + field * 4);
}
}
// Write comparison results to CR field

View File

@ -8,21 +8,6 @@
#include "Emu/Cell/lv2/sys_memory.h"
#include "Emu/RSX/GSRender.h"
#ifdef _WIN32
#include <Windows.h>
#else
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
/* OS X uses MAP_ANON instead of MAP_ANONYMOUS */
#ifndef MAP_ANONYMOUS
#define MAP_ANONYMOUS MAP_ANON
#endif
#endif
#include <atomic>
#include <deque>
@ -48,6 +33,9 @@ namespace vm
// Auxiliary virtual memory for executable areas
u8* const g_exec_addr = memory_reserve_4GiB((std::uintptr_t)g_base_addr);
// Stats for debugging
u8* const g_stat_addr = memory_reserve_4GiB((std::uintptr_t)g_exec_addr);
// Memory locations
std::vector<std::shared_ptr<block_t>> g_locations;
@ -349,16 +337,17 @@ namespace vm
}
}
void* real_addr = g_base_addr + addr;
void* exec_addr = g_exec_addr + addr;
utils::memory_commit(g_base_addr + addr, size);
#ifdef _WIN32
auto protection = flags & page_writable ? PAGE_READWRITE : (flags & page_readable ? PAGE_READONLY : PAGE_NOACCESS);
verify(__func__), ::VirtualAlloc(real_addr, size, MEM_COMMIT, protection);
#else
auto protection = flags & page_writable ? PROT_WRITE | PROT_READ : (flags & page_readable ? PROT_READ : PROT_NONE);
verify(__func__), !::mprotect(real_addr, size, protection), !::madvise(real_addr, size, MADV_WILLNEED);
#endif
if (flags & page_executable)
{
utils::memory_commit(g_exec_addr + addr, size);
}
if (g_cfg.core.ppu_debug && g_system == system_type::ps3)
{
utils::memory_commit(g_stat_addr + addr, size);
}
for (u32 i = addr / 4096; i < addr / 4096 + size / 4096; i++)
{
@ -415,15 +404,8 @@ namespace vm
{
if (u32 page_size = (i - start) * 4096)
{
#ifdef _WIN32
DWORD old;
auto protection = start_value & page_writable ? PAGE_READWRITE : (start_value & page_readable ? PAGE_READONLY : PAGE_NOACCESS);
verify(__func__), ::VirtualProtect(vm::base(start * 4096), page_size, protection, &old);
#else
auto protection = start_value & page_writable ? PROT_WRITE | PROT_READ : (start_value & page_readable ? PROT_READ : PROT_NONE);
verify(__func__), !::mprotect(vm::base(start * 4096), page_size, protection);
#endif
const auto protection = start_value & page_writable ? utils::protection::rw : (start_value & page_readable ? utils::protection::ro : utils::protection::no);
utils::memory_protect(g_base_addr + start * 4096, page_size, protection);
}
start_value = new_val;
@ -457,16 +439,13 @@ namespace vm
}
}
void* real_addr = g_base_addr + addr;
void* exec_addr = g_exec_addr + addr;
utils::memory_decommit(g_base_addr + addr, size);
utils::memory_decommit(g_exec_addr + addr, size);
#ifdef _WIN32
verify(__func__), ::VirtualFree(real_addr, size, MEM_DECOMMIT);
verify(__func__), ::VirtualFree(exec_addr, size, MEM_DECOMMIT);
#else
verify(__func__), ::mmap(real_addr, size, PROT_NONE, MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
verify(__func__), ::mmap(exec_addr, size, PROT_NONE, MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
#endif
if (g_cfg.core.ppu_debug && g_system == system_type::ps3)
{
utils::memory_decommit(g_stat_addr + addr, size);
}
}
bool check_addr(u32 addr, u32 size, u8 flags)
@ -856,6 +835,7 @@ namespace vm
utils::memory_decommit(g_base_addr, 0x100000000);
utils::memory_decommit(g_exec_addr, 0x100000000);
utils::memory_decommit(g_stat_addr, 0x100000000);
}
}

View File

@ -11,6 +11,7 @@ namespace vm
{
extern u8* const g_base_addr;
extern u8* const g_exec_addr;
extern u8* const g_stat_addr;
enum memory_location_t : uint
{

View File

@ -7,6 +7,7 @@
#include "Emu/Cell/PPUThread.h"
#include "Emu/Cell/PPUCallback.h"
#include "Emu/Cell/PPUOpcodes.h"
#include "Emu/Cell/PPUDisAsm.h"
#include "Emu/Cell/SPUThread.h"
#include "Emu/Cell/RawSPUThread.h"
#include "Emu/Cell/lv2/sys_sync.h"
@ -695,6 +696,37 @@ void Emulator::Resume()
m_pause_amend_time += get_system_time() - time;
}
// Print and reset debug data collected
if (m_state == system_state::paused && g_cfg.core.ppu_debug && g_system == system_type::ps3)
{
PPUDisAsm dis_asm(CPUDisAsm_InterpreterMode);
dis_asm.offset = vm::g_base_addr;
std::string dump;
for (u32 i = 0x10000; i < 0x40000000;)
{
if (vm::check_addr(i))
{
if (auto& data = *(be_t<u32>*)(vm::g_stat_addr + i))
{
dis_asm.dump_pc = i;
dis_asm.disasm(i);
fmt::append(dump, "\n\t'%08X' %s", data, dis_asm.last_opcode);
data = 0;
}
i += sizeof(u32);
}
else
{
i += 4096;
}
}
LOG_NOTICE(PPU, "[RESUME] Dumping instruction stats:%s", dump);
}
// Try to resume
if (!m_state.compare_and_swap_test(system_state::paused, system_state::running))
{