diff options
| author | 2020-10-13 18:00:25 -0300 | |
|---|---|---|
| committer | 2020-10-13 18:00:25 -0300 | |
| commit | b9a9b83bee124a86501905d0b75def4ccb1cb966 (patch) | |
| tree | 8e7a42cb87ec56c2fadf3e75a31b1ead0c22514f /src/core/hle/kernel/kernel.cpp | |
| parent | Merge pull request #3929 from FearlessTobi/ticket-keys (diff) | |
| download | yuzu-b9a9b83bee124a86501905d0b75def4ccb1cb966.tar.gz yuzu-b9a9b83bee124a86501905d0b75def4ccb1cb966.tar.xz yuzu-b9a9b83bee124a86501905d0b75def4ccb1cb966.zip | |
kernel: Implement host thread register methods without locking
Locks on GetCurrentHostThreadID were causing performance issues
according to Visual Studio's profiler. It was consuming twice the time
as arm_interface.Run(). The cost was not in the function itself but in
the lockinig it required.
Reimplement these functions using atomics and static storage instead of
an unordered_map. This is a side effect to avoid locking and using linked
lists for reads.
Replace unordered_map with a linear search.
Diffstat (limited to 'src/core/hle/kernel/kernel.cpp')
| -rw-r--r-- | src/core/hle/kernel/kernel.cpp | 66 |
1 files changed, 38 insertions, 28 deletions
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index f2b0fe2fd..96ca01194 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -7,7 +7,6 @@ | |||
| 7 | #include <bitset> | 7 | #include <bitset> |
| 8 | #include <functional> | 8 | #include <functional> |
| 9 | #include <memory> | 9 | #include <memory> |
| 10 | #include <mutex> | ||
| 11 | #include <thread> | 10 | #include <thread> |
| 12 | #include <unordered_map> | 11 | #include <unordered_map> |
| 13 | #include <utility> | 12 | #include <utility> |
| @@ -107,7 +106,11 @@ struct KernelCore::Impl { | |||
| 107 | cores.clear(); | 106 | cores.clear(); |
| 108 | 107 | ||
| 109 | exclusive_monitor.reset(); | 108 | exclusive_monitor.reset(); |
| 110 | host_thread_ids.clear(); | 109 | |
| 110 | num_host_threads = 0; | ||
| 111 | std::fill(register_host_thread_keys.begin(), register_host_thread_keys.end(), | ||
| 112 | std::thread::id{}); | ||
| 113 | std::fill(register_host_thread_values.begin(), register_host_thread_values.end(), 0); | ||
| 111 | } | 114 | } |
| 112 | 115 | ||
| 113 | void InitializePhysicalCores() { | 116 | void InitializePhysicalCores() { |
| @@ -177,54 +180,56 @@ struct KernelCore::Impl { | |||
| 177 | 180 | ||
| 178 | void MakeCurrentProcess(Process* process) { | 181 | void MakeCurrentProcess(Process* process) { |
| 179 | current_process = process; | 182 | current_process = process; |
| 180 | |||
| 181 | if (process == nullptr) { | 183 | if (process == nullptr) { |
| 182 | return; | 184 | return; |
| 183 | } | 185 | } |
| 184 | 186 | const u32 core_id = GetCurrentHostThreadID(); | |
| 185 | u32 core_id = GetCurrentHostThreadID(); | ||
| 186 | if (core_id < Core::Hardware::NUM_CPU_CORES) { | 187 | if (core_id < Core::Hardware::NUM_CPU_CORES) { |
| 187 | system.Memory().SetCurrentPageTable(*process, core_id); | 188 | system.Memory().SetCurrentPageTable(*process, core_id); |
| 188 | } | 189 | } |
| 189 | } | 190 | } |
| 190 | 191 | ||
| 191 | void RegisterCoreThread(std::size_t core_id) { | 192 | void RegisterCoreThread(std::size_t core_id) { |
| 192 | std::unique_lock lock{register_thread_mutex}; | 193 | const std::thread::id this_id = std::this_thread::get_id(); |
| 193 | if (!is_multicore) { | 194 | if (!is_multicore) { |
| 194 | single_core_thread_id = std::this_thread::get_id(); | 195 | single_core_thread_id = this_id; |
| 195 | } | 196 | } |
| 196 | const std::thread::id this_id = std::this_thread::get_id(); | 197 | const auto end = register_host_thread_keys.begin() + num_host_threads; |
| 197 | const auto it = host_thread_ids.find(this_id); | 198 | const auto it = std::find(register_host_thread_keys.begin(), end, this_id); |
| 198 | ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); | 199 | ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); |
| 199 | ASSERT(it == host_thread_ids.end()); | 200 | ASSERT(it == end); |
| 200 | ASSERT(!registered_core_threads[core_id]); | 201 | ASSERT(!registered_core_threads[core_id]); |
| 201 | host_thread_ids[this_id] = static_cast<u32>(core_id); | 202 | InsertHostThread(static_cast<u32>(core_id)); |
| 202 | registered_core_threads.set(core_id); | 203 | registered_core_threads.set(core_id); |
| 203 | } | 204 | } |
| 204 | 205 | ||
| 205 | void RegisterHostThread() { | 206 | void RegisterHostThread() { |
| 206 | std::unique_lock lock{register_thread_mutex}; | ||
| 207 | const std::thread::id this_id = std::this_thread::get_id(); | 207 | const std::thread::id this_id = std::this_thread::get_id(); |
| 208 | const auto it = host_thread_ids.find(this_id); | 208 | const auto end = register_host_thread_keys.begin() + num_host_threads; |
| 209 | if (it != host_thread_ids.end()) { | 209 | const auto it = std::find(register_host_thread_keys.begin(), end, this_id); |
| 210 | return; | 210 | if (it == end) { |
| 211 | InsertHostThread(registered_thread_ids++); | ||
| 211 | } | 212 | } |
| 212 | host_thread_ids[this_id] = registered_thread_ids++; | ||
| 213 | } | 213 | } |
| 214 | 214 | ||
| 215 | u32 GetCurrentHostThreadID() const { | 215 | void InsertHostThread(u32 value) { |
| 216 | const size_t index = num_host_threads++; | ||
| 217 | ASSERT_MSG(index < NUM_REGISTRABLE_HOST_THREADS, "Too many host threads"); | ||
| 218 | register_host_thread_values[index] = value; | ||
| 219 | register_host_thread_keys[index] = std::this_thread::get_id(); | ||
| 220 | } | ||
| 221 | |||
| 222 | [[nodiscard]] u32 GetCurrentHostThreadID() const { | ||
| 216 | const std::thread::id this_id = std::this_thread::get_id(); | 223 | const std::thread::id this_id = std::this_thread::get_id(); |
| 217 | if (!is_multicore) { | 224 | if (!is_multicore && single_core_thread_id == this_id) { |
| 218 | if (single_core_thread_id == this_id) { | 225 | return static_cast<u32>(system.GetCpuManager().CurrentCore()); |
| 219 | return static_cast<u32>(system.GetCpuManager().CurrentCore()); | ||
| 220 | } | ||
| 221 | } | 226 | } |
| 222 | std::unique_lock lock{register_thread_mutex}; | 227 | const auto end = register_host_thread_keys.begin() + num_host_threads; |
| 223 | const auto it = host_thread_ids.find(this_id); | 228 | const auto it = std::find(register_host_thread_keys.begin(), end, this_id); |
| 224 | if (it == host_thread_ids.end()) { | 229 | if (it == end) { |
| 225 | return Core::INVALID_HOST_THREAD_ID; | 230 | return Core::INVALID_HOST_THREAD_ID; |
| 226 | } | 231 | } |
| 227 | return it->second; | 232 | return register_host_thread_values[std::distance(register_host_thread_keys.begin(), it)]; |
| 228 | } | 233 | } |
| 229 | 234 | ||
| 230 | Core::EmuThreadHandle GetCurrentEmuThreadID() const { | 235 | Core::EmuThreadHandle GetCurrentEmuThreadID() const { |
| @@ -322,10 +327,15 @@ struct KernelCore::Impl { | |||
| 322 | std::vector<Kernel::PhysicalCore> cores; | 327 | std::vector<Kernel::PhysicalCore> cores; |
| 323 | 328 | ||
| 324 | // 0-3 IDs represent core threads, >3 represent others | 329 | // 0-3 IDs represent core threads, >3 represent others |
| 325 | std::unordered_map<std::thread::id, u32> host_thread_ids; | 330 | std::atomic<u32> registered_thread_ids{Core::Hardware::NUM_CPU_CORES}; |
| 326 | u32 registered_thread_ids{Core::Hardware::NUM_CPU_CORES}; | ||
| 327 | std::bitset<Core::Hardware::NUM_CPU_CORES> registered_core_threads; | 331 | std::bitset<Core::Hardware::NUM_CPU_CORES> registered_core_threads; |
| 328 | mutable std::mutex register_thread_mutex; | 332 | |
| 333 | // Number of host threads is a relatively high number to avoid overflowing | ||
| 334 | static constexpr size_t NUM_REGISTRABLE_HOST_THREADS = 64; | ||
| 335 | std::atomic<size_t> num_host_threads{0}; | ||
| 336 | std::array<std::atomic<std::thread::id>, NUM_REGISTRABLE_HOST_THREADS> | ||
| 337 | register_host_thread_keys{}; | ||
| 338 | std::array<std::atomic<u32>, NUM_REGISTRABLE_HOST_THREADS> register_host_thread_values{}; | ||
| 329 | 339 | ||
| 330 | // Kernel memory management | 340 | // Kernel memory management |
| 331 | std::unique_ptr<Memory::MemoryManager> memory_manager; | 341 | std::unique_ptr<Memory::MemoryManager> memory_manager; |