utils: Scale busy_wait according to arm timer frequency
> - This is a fatal issue that was impacting arm builds, since busy_waits were written assuming an approx 3Ghz x86 machine > and most arm machines have a hardware timer that runs south of 100mhz, meaning the top items in the profiler were calls to busy_wait(); > all over the code. Fixing this is a very significant speedup, on my snapdragon 8 gen 2 device. 27->37FPS in Metal Gear Rising, but almost > all games benefit when run on ARM.
This commit is contained in:
@@ -26,6 +26,7 @@
|
|||||||
#include "Utilities/sema.h"
|
#include "Utilities/sema.h"
|
||||||
#include "Utilities/date_time.h"
|
#include "Utilities/date_time.h"
|
||||||
#include "util/console.h"
|
#include "util/console.h"
|
||||||
|
#include "util/asm.hpp"
|
||||||
#include "Crypto/decrypt_binaries.h"
|
#include "Crypto/decrypt_binaries.h"
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include "module_verifier.hpp"
|
#include "module_verifier.hpp"
|
||||||
@@ -681,6 +682,10 @@ int run_rpcs3(int argc, char** argv)
|
|||||||
logs::set_init({std::move(ver), std::move(sys), std::move(os), std::move(qt), std::move(time)});
|
logs::set_init({std::move(ver), std::move(sys), std::move(os), std::move(qt), std::move(time)});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ARCH_ARM64
|
||||||
|
utils::init_arm_timer_scale();
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
sys_log.notice("Initialization times before main(): %fGc", intro_cycles / 1000000000.);
|
sys_log.notice("Initialization times before main(): %fGc", intro_cycles / 1000000000.);
|
||||||
#elif defined(RUSAGE_THREAD)
|
#elif defined(RUSAGE_THREAD)
|
||||||
|
|||||||
+27
-2
@@ -183,10 +183,35 @@ namespace utils
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Synchronization helper (cache-friendly busy waiting)
|
// The hardware clock on many arm timers run south of 100mhz
|
||||||
inline void busy_wait(usz cycles = 3000)
|
// and the busy waits in RPCS3 were written assuming an x86 machine
|
||||||
|
// with hardware timers that run around 3GHz.
|
||||||
|
// For instance, on the snapdragon 8 gen 2, the hardware timer runs at 19.2mhz.
|
||||||
|
// This means that a busy wait that would have taken nanoseconds on x86 will run for
|
||||||
|
// many microseconds on many arm machines.
|
||||||
|
#ifdef ARCH_ARM64
|
||||||
|
|
||||||
|
inline u64 arm_timer_scale = 1;
|
||||||
|
|
||||||
|
inline void init_arm_timer_scale()
|
||||||
{
|
{
|
||||||
|
u64 freq = 0;
|
||||||
|
asm volatile("mrs %0, cntfrq_el0" : "=r"(freq));
|
||||||
|
|
||||||
|
// Try to scale hardware timer to match 3GHz
|
||||||
|
u64 timer_scale = freq / 30000000;
|
||||||
|
if (timer_scale)
|
||||||
|
arm_timer_scale = timer_scale;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
inline void busy_wait(u64 cycles = 3000)
|
||||||
|
{
|
||||||
|
#ifdef ARCH_ARM64
|
||||||
|
const u64 stop = get_tsc() + ((cycles / 100) * arm_timer_scale);
|
||||||
|
#else
|
||||||
const u64 stop = get_tsc() + cycles;
|
const u64 stop = get_tsc() + cycles;
|
||||||
|
#endif
|
||||||
do pause();
|
do pause();
|
||||||
while (get_tsc() < stop);
|
while (get_tsc() < stop);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user