summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorJosJuice <josjuice@gmail.com>2025-06-30 19:12:00 +0200
committerJosJuice <josjuice@gmail.com>2025-07-27 16:26:47 +0200
commit803e6b017bf8bb82ee65b48fa244eb1e4c89034d (patch)
treeae337c9e6d6e4787d017061b14b01c2579fcabd7 /Source/Core
parent59d126d21582d2fd2df05dc33d5eeebaf097204a (diff)
PPCSymbolDB: Reduce lock contention in LoadMap/LoadMapOnBoot
By building the map in a local variable and then swapping it with the member variable, we avoid the need to hold a lock while building the map.
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/Common/SymbolDB.cpp10
-rw-r--r--Source/Core/Common/SymbolDB.h4
-rw-r--r--Source/Core/Core/PowerPC/PPCSymbolDB.cpp98
-rw-r--r--Source/Core/Core/PowerPC/PPCSymbolDB.h11
4 files changed, 84 insertions, 39 deletions
diff --git a/Source/Core/Common/SymbolDB.cpp b/Source/Core/Common/SymbolDB.cpp
index 88f281e497..ad438b8277 100644
--- a/Source/Core/Common/SymbolDB.cpp
+++ b/Source/Core/Common/SymbolDB.cpp
@@ -5,6 +5,7 @@
#include <cstring>
#include <map>
+#include <mutex>
#include <string>
#include <utility>
@@ -49,6 +50,8 @@ bool SymbolDB::IsEmpty() const
bool SymbolDB::Clear(const char* prefix)
{
+ std::lock_guard lock(m_mutex);
+
// TODO: honor prefix
m_map_name.clear();
if (IsEmpty())
@@ -62,8 +65,13 @@ bool SymbolDB::Clear(const char* prefix)
void SymbolDB::Index()
{
+ Index(&m_functions);
+}
+
+void SymbolDB::Index(XFuncMap* functions)
+{
int i = 0;
- for (auto& func : m_functions)
+ for (auto& func : *functions)
{
func.second.index = i++;
}
diff --git a/Source/Core/Common/SymbolDB.h b/Source/Core/Common/SymbolDB.h
index 7763999453..69515532b1 100644
--- a/Source/Core/Common/SymbolDB.h
+++ b/Source/Core/Common/SymbolDB.h
@@ -7,6 +7,7 @@
#pragma once
#include <map>
+#include <mutex>
#include <set>
#include <string>
#include <string_view>
@@ -105,9 +106,12 @@ public:
void Index();
protected:
+ static void Index(XFuncMap* functions);
+
XFuncMap m_functions;
XNoteMap m_notes;
XFuncPtrMap m_checksum_to_function;
std::string m_map_name;
+ std::mutex m_mutex;
};
} // namespace Common
diff --git a/Source/Core/Core/PowerPC/PPCSymbolDB.cpp b/Source/Core/Core/PowerPC/PPCSymbolDB.cpp
index e7bf9bd923..51fb3eaa62 100644
--- a/Source/Core/Core/PowerPC/PPCSymbolDB.cpp
+++ b/Source/Core/Core/PowerPC/PPCSymbolDB.cpp
@@ -56,8 +56,17 @@ void PPCSymbolDB::AddKnownSymbol(const Core::CPUThreadGuard& guard, u32 startAdd
const std::string& name, const std::string& object_name,
Common::Symbol::Type type)
{
- auto iter = m_functions.find(startAddr);
- if (iter != m_functions.end())
+ AddKnownSymbol(guard, startAddr, size, name, object_name, type, &m_functions,
+ &m_checksum_to_function);
+}
+
+void PPCSymbolDB::AddKnownSymbol(const Core::CPUThreadGuard& guard, u32 startAddr, u32 size,
+ const std::string& name, const std::string& object_name,
+ Common::Symbol::Type type, XFuncMap* functions,
+ XFuncPtrMap* checksum_to_function)
+{
+ auto iter = functions->find(startAddr);
+ if (iter != functions->end())
{
// already got it, let's just update name, checksum & size to be sure.
Common::Symbol* tempfunc = &iter->second;
@@ -70,7 +79,7 @@ void PPCSymbolDB::AddKnownSymbol(const Core::CPUThreadGuard& guard, u32 startAdd
else
{
// new symbol. run analyze.
- auto& new_symbol = m_functions.emplace(startAddr, name).first->second;
+ auto& new_symbol = functions->emplace(startAddr, name).first->second;
new_symbol.object_name = object_name;
new_symbol.type = type;
new_symbol.address = startAddr;
@@ -85,7 +94,7 @@ void PPCSymbolDB::AddKnownSymbol(const Core::CPUThreadGuard& guard, u32 startAdd
name, size, new_symbol.size);
new_symbol.size = size;
}
- m_checksum_to_function[new_symbol.hash].insert(&new_symbol);
+ (*checksum_to_function)[new_symbol.hash].insert(&new_symbol);
}
else
{
@@ -96,9 +105,14 @@ void PPCSymbolDB::AddKnownSymbol(const Core::CPUThreadGuard& guard, u32 startAdd
void PPCSymbolDB::AddKnownNote(u32 start_addr, u32 size, const std::string& name)
{
- auto iter = m_notes.find(start_addr);
+ AddKnownNote(start_addr, size, name, &m_notes);
+}
- if (iter != m_notes.end())
+void PPCSymbolDB::AddKnownNote(u32 start_addr, u32 size, const std::string& name, XNoteMap* notes)
+{
+ auto iter = notes->find(start_addr);
+
+ if (iter != notes->end())
{
// Already got it, just update the name and size.
Common::Note* tempfunc = &iter->second;
@@ -112,22 +126,27 @@ void PPCSymbolDB::AddKnownNote(u32 start_addr, u32 size, const std::string& name
tf.address = start_addr;
tf.size = size;
- m_notes[start_addr] = tf;
+ (*notes)[start_addr] = tf;
}
}
void PPCSymbolDB::DetermineNoteLayers()
{
- if (m_notes.empty())
+ DetermineNoteLayers(&m_notes);
+}
+
+void PPCSymbolDB::DetermineNoteLayers(XNoteMap* notes)
+{
+ if (notes->empty())
return;
- for (auto& note : m_notes)
+ for (auto& note : *notes)
note.second.layer = 0;
- for (auto iter = m_notes.begin(); iter != m_notes.end(); ++iter)
+ for (auto iter = notes->begin(); iter != notes->end(); ++iter)
{
const u32 range = iter->second.address + iter->second.size;
- auto search = m_notes.lower_bound(range);
+ auto search = notes->lower_bound(range);
while (--search != iter)
search->second.layer += 1;
@@ -312,21 +331,19 @@ bool PPCSymbolDB::FindMapFile(std::string* existing_map_file, std::string* writa
// Returns true if m_functions was changed.
bool PPCSymbolDB::LoadMapOnBoot(const Core::CPUThreadGuard& guard)
{
- std::lock_guard lock(m_mutex);
-
std::string existing_map_file;
if (!PPCSymbolDB::FindMapFile(&existing_map_file, nullptr))
return Clear();
- // If the map is already loaded (such as restarting the same game), skip reloading.
- if (!IsEmpty() && existing_map_file == m_map_name)
- return false;
-
- // Load map into cleared m_functions.
- bool changed = Clear();
+ {
+ std::lock_guard lock(m_mutex);
+ // If the map is already loaded (such as restarting the same game), skip reloading.
+ if (!IsEmpty() && existing_map_file == m_map_name)
+ return false;
+ }
- if (!LoadMap(guard, existing_map_file))
- return changed;
+ if (!LoadMap(guard, std::move(existing_map_file)))
+ return Clear();
return true;
}
@@ -338,14 +355,11 @@ bool PPCSymbolDB::LoadMapOnBoot(const Core::CPUThreadGuard& guard)
// function names and addresses that have a BLR before the start and at the end, but ignore any that
// don't, and then tell you how many were good and how many it ignored. That way you either find out
// it is all good and use it, find out it is partly good and use the good part, or find out that
-// only
-// a handful of functions lined up by coincidence and then you can clear the symbols. In the future
-// I
-// want to make it smarter, so it checks that there are no BLRs in the middle of the function
-// (by checking the code length), and also make it cope with added functions in the middle or work
-// based on the order of the functions and their approximate length. Currently that process has to
-// be
-// done manually and is very tedious.
+// only a handful of functions lined up by coincidence and then you can clear the symbols. In the
+// future I want to make it smarter, so it checks that there are no BLRs in the middle of the
+// function (by checking the code length), and also make it cope with added functions in the middle
+// or work based on the order of the functions and their approximate length. Currently that process
+// has to be done manually and is very tedious.
// The use case for separate handling of map files that aren't bad is that you usually want to also
// load names that aren't functions(if included in the map file) without them being rejected as
// invalid.
@@ -356,12 +370,16 @@ bool PPCSymbolDB::LoadMapOnBoot(const Core::CPUThreadGuard& guard)
// This one can load both leftover map files on game discs (like Zelda), and mapfiles
// produced by SaveSymbolMap below.
// bad=true means carefully load map files that might not be from exactly the right version
-bool PPCSymbolDB::LoadMap(const Core::CPUThreadGuard& guard, const std::string& filename, bool bad)
+bool PPCSymbolDB::LoadMap(const Core::CPUThreadGuard& guard, std::string filename, bool bad)
{
File::IOFile f(filename, "r");
if (!f)
return false;
+ XFuncMap new_functions;
+ XNoteMap new_notes;
+ XFuncPtrMap checksum_to_function;
+
// Two columns are used by Super Smash Bros. Brawl Korean map file
// Three columns are commonly used
// Four columns are used in American Mensa Academy map files and perhaps other games
@@ -573,9 +591,14 @@ bool PPCSymbolDB::LoadMap(const Core::CPUThreadGuard& guard, const std::string&
++good_count;
if (section_name == ".note")
- AddKnownNote(vaddress, size, name);
+ {
+ AddKnownNote(vaddress, size, name, &new_notes);
+ }
else
- AddKnownSymbol(guard, vaddress, size, name_string, object_filename_string, type);
+ {
+ AddKnownSymbol(guard, vaddress, size, name_string, object_filename_string, type,
+ &new_functions, &checksum_to_function);
+ }
}
else
{
@@ -584,10 +607,15 @@ bool PPCSymbolDB::LoadMap(const Core::CPUThreadGuard& guard, const std::string&
}
}
- m_map_name = filename;
+ Index(&new_functions);
+ DetermineNoteLayers(&new_notes);
+
+ std::lock_guard lock(m_mutex);
+ std::swap(m_functions, new_functions);
+ std::swap(m_notes, new_notes);
+ std::swap(m_checksum_to_function, checksum_to_function);
+ std::swap(m_map_name, filename);
- Index();
- DetermineNoteLayers();
NOTICE_LOG_FMT(SYMBOLS, "{} symbols loaded, {} symbols ignored.", good_count, bad_count);
return true;
}
diff --git a/Source/Core/Core/PowerPC/PPCSymbolDB.h b/Source/Core/Core/PowerPC/PPCSymbolDB.h
index b182023a54..079328147d 100644
--- a/Source/Core/Core/PowerPC/PPCSymbolDB.h
+++ b/Source/Core/Core/PowerPC/PPCSymbolDB.h
@@ -3,7 +3,6 @@
#pragma once
-#include <mutex>
#include <string>
#include <string_view>
@@ -40,7 +39,7 @@ public:
void FillInCallers();
bool LoadMapOnBoot(const Core::CPUThreadGuard& guard);
- bool LoadMap(const Core::CPUThreadGuard& guard, const std::string& filename, bool bad = false);
+ bool LoadMap(const Core::CPUThreadGuard& guard, std::string filename, bool bad = false);
bool SaveSymbolMap(const std::string& filename) const;
bool SaveCodeMap(const Core::CPUThreadGuard& guard, const std::string& filename) const;
@@ -51,5 +50,11 @@ public:
static bool FindMapFile(std::string* existing_map_file, std::string* writable_map_file);
private:
- std::mutex m_mutex;
+ static void AddKnownSymbol(const Core::CPUThreadGuard& guard, u32 startAddr, u32 size,
+ const std::string& name, const std::string& object_name,
+ Common::Symbol::Type type, XFuncMap* functions,
+ XFuncPtrMap* checksum_to_function);
+ static void AddKnownNote(u32 start_addr, u32 size, const std::string& name, XNoteMap* notes);
+
+ static void DetermineNoteLayers(XNoteMap* notes);
};