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 bbf72e79f9
4 changed files with 60 additions and 36 deletions

View File

@ -255,6 +255,8 @@ MemChecks::TMemChecksStr MemChecks::GetStrings() const
void MemChecks::AddFromStrings(const TMemChecksStr& mc_strings) void MemChecks::AddFromStrings(const TMemChecksStr& mc_strings)
{ {
const Core::CPUThreadGuard guard(m_system);
for (const std::string& mc_string : mc_strings) for (const std::string& mc_string : mc_strings)
{ {
TMemCheck mc; TMemCheck mc;
@ -281,15 +283,16 @@ void MemChecks::AddFromStrings(const TMemChecksStr& mc_strings)
mc.condition = Expression::TryParse(condition); 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); const Core::CPUThreadGuard guard(m_system);
// Check for existing breakpoint, and overwrite with new info. // Check for existing breakpoint, and overwrite with new info.
// This is assuming we usually want the new breakpoint over an old one. // This is assuming we usually want the new breakpoint over an old one.
const u32 address = memory_check.start_address; 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)); 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 (update)
if (!had_any) Update();
m_system.GetJitInterface().ClearCache(guard);
m_system.GetMMU().DBATUpdated();
} }
bool MemChecks::ToggleEnable(u32 address) bool MemChecks::ToggleEnable(u32 address)
@ -325,7 +326,7 @@ bool MemChecks::ToggleEnable(u32 address)
return true; return true;
} }
bool MemChecks::Remove(u32 address) bool MemChecks::Remove(u32 address, bool update)
{ {
const auto iter = const auto iter =
std::find_if(m_mem_checks.cbegin(), m_mem_checks.cend(), 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); const Core::CPUThreadGuard guard(m_system);
m_mem_checks.erase(iter); m_mem_checks.erase(iter);
if (!HasAny())
m_system.GetJitInterface().ClearCache(guard); if (update)
m_system.GetMMU().DBATUpdated(); Update();
return true; return true;
} }
@ -346,7 +348,20 @@ void MemChecks::Clear()
{ {
const Core::CPUThreadGuard guard(m_system); const Core::CPUThreadGuard guard(m_system);
m_mem_checks.clear(); 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(); m_system.GetMMU().DBATUpdated();
} }

View File

@ -115,19 +115,20 @@ public:
TMemChecksStr GetStrings() const; TMemChecksStr GetStrings() const;
void AddFromStrings(const TMemChecksStr& mc_strings); void AddFromStrings(const TMemChecksStr& mc_strings);
void Add(TMemCheck memory_check); void Add(TMemCheck memory_check, bool update = true);
bool ToggleEnable(u32 address); bool ToggleEnable(u32 address);
TMemCheck* GetMemCheck(u32 address, size_t size = 1); TMemCheck* GetMemCheck(u32 address, size_t size = 1);
bool OverlapsMemcheck(u32 address, u32 length) const; bool OverlapsMemcheck(u32 address, u32 length) const;
// Remove Breakpoint. Returns whether it was removed. bool Remove(u32 address, bool update = true);
bool Remove(u32 address);
void Update();
void Clear(); void Clear();
bool HasAny() const { return !m_mem_checks.empty(); } bool HasAny() const { return !m_mem_checks.empty(); }
private: private:
TMemChecks m_mem_checks; TMemChecks m_mem_checks;
Core::System& m_system; 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(); auto& memchecks = Core::System::GetInstance().GetPowerPC().GetMemChecks();
while (memchecks.GetMemCheck(addr, len) != nullptr) 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); INFO_LOG_FMT(GDB_STUB, "gdb: removed a memcheck: {:08x} bytes at {:08x}", len, addr);
} }
memchecks.Update();
} }
Host_PPCBreakpointsChanged(); Host_PPCBreakpointsChanged();
} }

View File

@ -817,29 +817,36 @@ void MemoryViewWidget::ToggleBreakpoint(u32 addr, bool row)
if (row && memchecks.OverlapsMemcheck(addr, m_bytes_per_row)) if (row && memchecks.OverlapsMemcheck(addr, m_bytes_per_row))
overlap = true; overlap = true;
for (int i = 0; i < breaks; i++)
{ {
u32 address = addr + length * i; const Core::CPUThreadGuard guard(m_system);
TMemCheck* check_ptr = memchecks.GetMemCheck(address, length);
if (check_ptr == nullptr && !overlap) for (int i = 0; i < breaks; i++)
{ {
TMemCheck check; u32 address = addr + length * i;
check.start_address = address; TMemCheck* check_ptr = memchecks.GetMemCheck(address, length);
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)); if (check_ptr == nullptr && !overlap)
} {
else if (check_ptr != nullptr) TMemCheck check;
{ check.start_address = address;
// Using the pointer fixes misaligned breakpoints (0x11 breakpoint in 0x10 aligned view). check.end_address = check.start_address + length - 1;
memchecks.Remove(check_ptr->start_address); 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(); emit Host::GetInstance()->PPCBreakpointsChanged();