diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index b46668a409..202af8f01b 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -20,6 +20,7 @@ target_sources(common PRIVATE FastJmp.cpp IniInterface.cpp Mutex.cpp + Misc.cpp PathUtils.cpp PrecompiledHeader.cpp Perf.cpp diff --git a/common/General.h b/common/General.h index 3329c0e320..afc9849781 100644 --- a/common/General.h +++ b/common/General.h @@ -217,6 +217,11 @@ extern void InitCPUTicks(); extern u64 GetTickFrequency(); extern u64 GetCPUTicks(); extern u64 GetPhysicalMemory(); +/// Spin for a short period of time (call while spinning waiting for a lock) +/// Returns the approximate number of ns that passed +extern u32 ShortSpin(); +/// Number of ns to spin for before sleeping a thread +extern const u32 SPIN_TIME_NS; extern wxString GetOSVersionString(); diff --git a/common/Misc.cpp b/common/Misc.cpp new file mode 100644 index 0000000000..b2d9af41d1 --- /dev/null +++ b/common/Misc.cpp @@ -0,0 +1,73 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2021 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +#include "General.h" + +static u32 PAUSE_TIME = 0; + +static void MultiPause() +{ + _mm_pause(); + _mm_pause(); + _mm_pause(); + _mm_pause(); + _mm_pause(); + _mm_pause(); + _mm_pause(); + _mm_pause(); +} + +__noinline static void UpdatePauseTime() +{ + u64 start = GetCPUTicks(); + for (int i = 0; i < 64; i++) + { + MultiPause(); + } + u64 time = GetCPUTicks() - start; + u64 nanos = (time * 1000000000) / GetTickFrequency(); + PAUSE_TIME = (nanos / 64) + 1; +} + +u32 ShortSpin() +{ + u32 inc = PAUSE_TIME; + if (unlikely(inc == 0)) + { + UpdatePauseTime(); + inc = PAUSE_TIME; + } + + u32 time = 0; + // Sleep for approximately 500ns + for (; time < 500; time += inc) + MultiPause(); + + return time; +} + +static u32 GetSpinTime() +{ + if (char* req = getenv("WAIT_SPIN_MICROSECONDS")) + { + return 1000 * atoi(req); + } + else + { + return 50 * 1000; // 50µs + } +} + +const u32 SPIN_TIME_NS = GetSpinTime(); diff --git a/common/common.vcxproj b/common/common.vcxproj index d1afc0d505..a9eb69c152 100644 --- a/common/common.vcxproj +++ b/common/common.vcxproj @@ -67,6 +67,7 @@ + diff --git a/common/common.vcxproj.filters b/common/common.vcxproj.filters index 79099f3206..81fc51b00a 100644 --- a/common/common.vcxproj.filters +++ b/common/common.vcxproj.filters @@ -55,6 +55,9 @@ Source Files + + Source Files + Source Files