Make memory breakpoint faster

Currently, slowmem is used at any time that memory breakpoints are in use.  This commit makes it so that whenever the DBAT gets updated, if the address is overllaping any memchecks, it forces the use of slowmem.  This allows to keep fastmem for any other cases and noticably increases performance when using memory breakpoints.
This commit is contained in:
aldelaro5 2017-02-24 21:10:22 -05:00
parent 0a8b5b79ef
commit 52fe05af6b
7 changed files with 39 additions and 25 deletions

View File

@ -11,8 +11,10 @@
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/DebugInterface.h" #include "Common/DebugInterface.h"
#include "Core/Core.h"
#include "Core/PowerPC/JitCommon/JitBase.h" #include "Core/PowerPC/JitCommon/JitBase.h"
#include "Core/PowerPC/JitCommon/JitCache.h" #include "Core/PowerPC/JitCommon/JitCache.h"
#include "Core/PowerPC/PowerPC.h"
bool BreakPoints::IsAddressBreakPoint(u32 address) const bool BreakPoints::IsAddressBreakPoint(u32 address) const
{ {
@ -168,13 +170,18 @@ void MemChecks::AddFromStrings(const TMemChecksStr& mc_strings)
void MemChecks::Add(const TMemCheck& memory_check) void MemChecks::Add(const TMemCheck& memory_check)
{ {
bool had_any = HasAny();
if (GetMemCheck(memory_check.start_address) == nullptr) if (GetMemCheck(memory_check.start_address) == nullptr)
{
bool had_any = HasAny();
m_mem_checks.push_back(memory_check); m_mem_checks.push_back(memory_check);
// If this is the first one, clear the JIT cache so it can switch to bool lock = Core::PauseAndLock(true);
// watchpoint-compatible code. // If this is the first one, clear the JIT cache so it can switch to
if (!had_any && g_jit) // watchpoint-compatible code.
g_jit->GetBlockCache()->SchedulateClearCacheThreadSafe(); if (!had_any && g_jit)
g_jit->ClearCache();
PowerPC::DBATUpdated();
Core::PauseAndLock(false, lock);
}
} }
void MemChecks::Remove(u32 address) void MemChecks::Remove(u32 address)
@ -184,8 +191,11 @@ void MemChecks::Remove(u32 address)
if (i->start_address == address) if (i->start_address == address)
{ {
m_mem_checks.erase(i); m_mem_checks.erase(i);
bool lock = Core::PauseAndLock(true);
if (!HasAny() && g_jit) if (!HasAny() && g_jit)
g_jit->GetBlockCache()->SchedulateClearCacheThreadSafe(); g_jit->ClearCache();
PowerPC::DBATUpdated();
Core::PauseAndLock(false, lock);
return; return;
} }
} }

View File

@ -335,7 +335,7 @@ void EmuCodeBlock::MMIOLoadToReg(MMIO::Mapping* mmio, Gen::X64Reg reg_value,
void EmuCodeBlock::SafeLoadToReg(X64Reg reg_value, const Gen::OpArg& opAddress, int accessSize, void EmuCodeBlock::SafeLoadToReg(X64Reg reg_value, const Gen::OpArg& opAddress, int accessSize,
s32 offset, BitSet32 registersInUse, bool signExtend, int flags) s32 offset, BitSet32 registersInUse, bool signExtend, int flags)
{ {
bool slowmem = (flags & SAFE_LOADSTORE_FORCE_SLOWMEM) != 0 || g_jit->jo.alwaysUseMemFuncs; bool slowmem = (flags & SAFE_LOADSTORE_FORCE_SLOWMEM) != 0;
registersInUse[reg_value] = false; registersInUse[reg_value] = false;
if (g_jit->jo.fastmem && !(flags & SAFE_LOADSTORE_NO_FASTMEM) && !slowmem) if (g_jit->jo.fastmem && !(flags & SAFE_LOADSTORE_NO_FASTMEM) && !slowmem)
@ -492,7 +492,7 @@ void EmuCodeBlock::SafeWriteRegToReg(OpArg reg_value, X64Reg reg_addr, int acces
BitSet32 registersInUse, int flags) BitSet32 registersInUse, int flags)
{ {
bool swap = !(flags & SAFE_LOADSTORE_NO_SWAP); bool swap = !(flags & SAFE_LOADSTORE_NO_SWAP);
bool slowmem = (flags & SAFE_LOADSTORE_FORCE_SLOWMEM) != 0 || g_jit->jo.alwaysUseMemFuncs; bool slowmem = (flags & SAFE_LOADSTORE_FORCE_SLOWMEM) != 0;
// set the correct immediate format // set the correct immediate format
reg_value = FixImmediate(accessSize, reg_value); reg_value = FixImmediate(accessSize, reg_value);

View File

@ -46,7 +46,6 @@ bool JitBase::MergeAllowedNextInstructions(int count)
void JitBase::UpdateMemoryOptions() void JitBase::UpdateMemoryOptions()
{ {
bool any_watchpoints = PowerPC::memchecks.HasAny(); bool any_watchpoints = PowerPC::memchecks.HasAny();
jo.fastmem = SConfig::GetInstance().bFastmem && !any_watchpoints; jo.fastmem = SConfig::GetInstance().bFastmem;
jo.memcheck = SConfig::GetInstance().bMMU || any_watchpoints; jo.memcheck = SConfig::GetInstance().bMMU || any_watchpoints;
jo.alwaysUseMemFuncs = any_watchpoints;
} }

View File

@ -52,7 +52,6 @@ protected:
bool accurateSinglePrecision; bool accurateSinglePrecision;
bool fastmem; bool fastmem;
bool memcheck; bool memcheck;
bool alwaysUseMemFuncs;
}; };
struct JitState struct JitState
{ {

View File

@ -29,13 +29,6 @@
using namespace Gen; using namespace Gen;
static CoreTiming::EventType* s_clear_jit_cache_thread_safe;
static void ClearCacheThreadSafe(u64 userdata, s64 cyclesdata)
{
JitInterface::ClearCache();
}
bool JitBlock::OverlapsPhysicalRange(u32 address, u32 length) const bool JitBlock::OverlapsPhysicalRange(u32 address, u32 length) const
{ {
return physical_addresses.lower_bound(address) != return physical_addresses.lower_bound(address) !=
@ -50,7 +43,6 @@ JitBaseBlockCache::~JitBaseBlockCache() = default;
void JitBaseBlockCache::Init() void JitBaseBlockCache::Init()
{ {
s_clear_jit_cache_thread_safe = CoreTiming::RegisterEvent("clearJitCache", ClearCacheThreadSafe);
JitRegister::Init(SConfig::GetInstance().m_perfDir); JitRegister::Init(SConfig::GetInstance().m_perfDir);
Clear(); Clear();
@ -89,11 +81,6 @@ void JitBaseBlockCache::Reset()
Init(); Init();
} }
void JitBaseBlockCache::SchedulateClearCacheThreadSafe()
{
CoreTiming::ScheduleEvent(0, s_clear_jit_cache_thread_safe, 0, CoreTiming::FromThread::NON_CPU);
}
JitBlock** JitBaseBlockCache::GetFastBlockMap() JitBlock** JitBaseBlockCache::GetFastBlockMap()
{ {
return fast_block_map.data(); return fast_block_map.data();

View File

@ -125,7 +125,6 @@ public:
void Shutdown(); void Shutdown();
void Clear(); void Clear();
void Reset(); void Reset();
void SchedulateClearCacheThreadSafe();
// Code Cache // Code Cache
JitBlock** GetFastBlockMap(); JitBlock** GetFastBlockMap();

View File

@ -1132,6 +1132,24 @@ static TranslateAddressResult TranslatePageAddress(const u32 address, const XChe
return TranslateAddressResult{TranslateAddressResult::PAGE_FAULT, 0}; return TranslateAddressResult{TranslateAddressResult::PAGE_FAULT, 0};
} }
static bool overlaps_memcheck(u32 pageEndAddress)
{
if (!memchecks.HasAny())
return false;
u32 page_end_suffix = ((1 << BAT_INDEX_SHIFT)) - 1;
for (TMemCheck memcheck : memchecks.GetMemChecks())
{
if (((memcheck.start_address | page_end_suffix) == pageEndAddress ||
(memcheck.end_address | page_end_suffix) == pageEndAddress) ||
((memcheck.start_address | page_end_suffix) < pageEndAddress &&
(memcheck.end_address | page_end_suffix) > pageEndAddress))
{
return true;
}
}
return false;
}
static void UpdateBATs(BatTable& bat_table, u32 base_spr) static void UpdateBATs(BatTable& bat_table, u32 base_spr)
{ {
// TODO: Separate BATs for MSR.PR==0 and MSR.PR==1 // TODO: Separate BATs for MSR.PR==0 and MSR.PR==1
@ -1191,6 +1209,8 @@ static void UpdateBATs(BatTable& bat_table, u32 base_spr)
valid_bit = 0x3; valid_bit = 0x3;
else if ((address >> 28) == 0xE && (address < (0xE0000000 + Memory::L1_CACHE_SIZE))) else if ((address >> 28) == 0xE && (address < (0xE0000000 + Memory::L1_CACHE_SIZE)))
valid_bit = 0x3; valid_bit = 0x3;
if (overlaps_memcheck(((batu.BEPI | j) << BAT_INDEX_SHIFT) | ((1 << BAT_INDEX_SHIFT) - 1)))
valid_bit &= ~0x2;
// (BEPI | j) == (BEPI & ~BL) | (j & BL). // (BEPI | j) == (BEPI & ~BL) | (j & BL).
bat_table[batu.BEPI | j] = address | valid_bit; bat_table[batu.BEPI | j] = address | valid_bit;