Breakpoints: Fix lag when adding or removing multiple memory breakpoints by only calling DBATUpdated() once.

This commit is contained in:
TryTwo 2023-11-27 17:08:31 -07:00
parent 696b363f47
commit 05bf321a0c
4 changed files with 59 additions and 37 deletions

View File

@ -255,6 +255,8 @@ MemChecks::TMemChecksStr MemChecks::GetStrings() const
void MemChecks::AddFromStrings(const TMemChecksStr& mc_strings)
{
const Core::CPUThreadGuard guard(m_system);
for (const std::string& mc_string : mc_strings)
{
TMemCheck mc;
@ -281,15 +283,16 @@ void MemChecks::AddFromStrings(const TMemChecksStr& mc_strings)
mc.condition = Expression::TryParse(condition);
}
Add(std::move(mc));
Add(std::move(mc), false);
}
Update();
}
void MemChecks::Add(TMemCheck memory_check)
void MemChecks::Add(TMemCheck memory_check, bool update)
{
bool had_any = HasAny();
const Core::CPUThreadGuard guard(m_system);
// Check for existing breakpoint, and overwrite with new info.
// This is assuming we usually want the new breakpoint over an old one.
const u32 address = memory_check.start_address;
@ -306,11 +309,9 @@ void MemChecks::Add(TMemCheck memory_check)
{
m_mem_checks.emplace_back(std::move(memory_check));
}
// If this is the first one, clear the JIT cache so it can switch to
// watchpoint-compatible code.
if (!had_any)
m_system.GetJitInterface().ClearCache(guard);
m_system.GetMMU().DBATUpdated();
if (update)
Update();
}
bool MemChecks::ToggleEnable(u32 address)
@ -325,7 +326,7 @@ bool MemChecks::ToggleEnable(u32 address)
return true;
}
bool MemChecks::Remove(u32 address)
bool MemChecks::Remove(u32 address, bool update)
{
const auto iter =
std::find_if(m_mem_checks.cbegin(), m_mem_checks.cend(),
@ -336,9 +337,10 @@ bool MemChecks::Remove(u32 address)
const Core::CPUThreadGuard guard(m_system);
m_mem_checks.erase(iter);
if (!HasAny())
m_system.GetJitInterface().ClearCache(guard);
m_system.GetMMU().DBATUpdated();
if (update)
Update();
return true;
}
@ -346,7 +348,20 @@ void MemChecks::Clear()
{
const Core::CPUThreadGuard guard(m_system);
m_mem_checks.clear();
m_system.GetJitInterface().ClearCache(guard);
Update();
}
void MemChecks::Update()
{
const Core::CPUThreadGuard guard(m_system);
// Clear the JIT cache so it can switch the watchpoint-compatible mode.
if (m_mem_breakpoints_set != HasAny())
{
m_system.GetJitInterface().ClearCache(guard);
m_mem_breakpoints_set = HasAny();
}
m_system.GetMMU().DBATUpdated();
}

View File

@ -115,19 +115,20 @@ public:
TMemChecksStr GetStrings() const;
void AddFromStrings(const TMemChecksStr& mc_strings);
void Add(TMemCheck memory_check);
void Add(TMemCheck memory_check, bool update = true);
bool ToggleEnable(u32 address);
TMemCheck* GetMemCheck(u32 address, size_t size = 1);
bool OverlapsMemcheck(u32 address, u32 length) const;
// Remove Breakpoint. Returns whether it was removed.
bool Remove(u32 address);
bool Remove(u32 address, bool update = true);
void Update();
void Clear();
bool HasAny() const { return !m_mem_checks.empty(); }
private:
TMemChecks m_mem_checks;
Core::System& m_system;
bool m_mem_breakpoints_set = false;
};

View File

@ -174,9 +174,10 @@ static void RemoveBreakpoint(BreakpointType type, u32 addr, u32 len)
auto& memchecks = Core::System::GetInstance().GetPowerPC().GetMemChecks();
while (memchecks.GetMemCheck(addr, len) != nullptr)
{
memchecks.Remove(addr);
memchecks.Remove(addr, false);
INFO_LOG_FMT(GDB_STUB, "gdb: removed a memcheck: {:08x} bytes at {:08x}", len, addr);
}
memchecks.Update();
}
Host_PPCBreakpointsChanged();
}

View File

@ -817,31 +817,36 @@ void MemoryViewWidget::ToggleBreakpoint(u32 addr, bool row)
if (row && memchecks.OverlapsMemcheck(addr, m_bytes_per_row))
overlap = true;
for (int i = 0; i < breaks; i++)
{
u32 address = addr + length * i;
TMemCheck* check_ptr = memchecks.GetMemCheck(address, length);
if (check_ptr == nullptr && !overlap)
const Core::CPUThreadGuard guard(m_system);
for (int i = 0; i < breaks; i++)
{
TMemCheck check;
check.start_address = address;
check.end_address = check.start_address + length - 1;
check.is_ranged = length > 0;
check.is_break_on_read = (m_bp_type == BPType::ReadOnly || m_bp_type == BPType::ReadWrite);
check.is_break_on_write = (m_bp_type == BPType::WriteOnly || m_bp_type == BPType::ReadWrite);
check.log_on_hit = m_do_log;
check.break_on_hit = true;
u32 address = addr + length * i;
TMemCheck* check_ptr = memchecks.GetMemCheck(address, length);
memchecks.Add(std::move(check));
}
else if (check_ptr != nullptr)
{
// Using the pointer fixes misaligned breakpoints (0x11 breakpoint in 0x10 aligned view).
memchecks.Remove(check_ptr->start_address);
if (check_ptr == nullptr && !overlap)
{
TMemCheck check;
check.start_address = address;
check.end_address = check.start_address + length - 1;
check.is_ranged = length > 0;
check.is_break_on_read = (m_bp_type == BPType::ReadOnly || m_bp_type == BPType::ReadWrite);
check.is_break_on_write =
(m_bp_type == BPType::WriteOnly || m_bp_type == BPType::ReadWrite);
check.log_on_hit = m_do_log;
check.break_on_hit = true;
memchecks.Add(std::move(check), false);
}
else if (check_ptr != nullptr)
{
// Using the pointer fixes misaligned breakpoints (0x11 breakpoint in 0x10 aligned view).
memchecks.Remove(check_ptr->start_address, false);
}
}
}
memchecks.Update();
emit Host::GetInstance()->PPCBreakpointsChanged();
}