mirror of
https://github.com/ARMSX2/ARMSX3.git
synced 2026-08-24 16:58:52 -07:00
RSX: fall back to event-stream wait when the semaphore spin does not park
The one-shot cacheline wait (ldaxr-armed WFE) used in semaphore_acquire does not park on every core. Measured on Snapdragon 8 Elite class (Oryon, Odin 3): WFE returns immediately while the exclusive monitor is armed (~28.8M wakes/s in a standalone microbenchmark, vs ~20-30k/s for bare WFE and sevl+wfe), so the acquire loop ran at ~57M iterations/s through waits averaging 33 ms - about 99% of the RSX thread's wall time at a menu, with each iteration also paying the driver-recovery get_system_time() check. Keep the armed one-shot for the first 500 iterations of a wait - on cores where it parks it keeps its instant wake-on-write, and where it does not it acts as a short spin that still catches quick signals - then fall back to wait_for_event(), which parks on both classes and bounds wake latency at the architected event-stream period (~50 us measured). Measured on device (Mirror's Edge, MT RSX on, state-verified windows): menu instructions -55% (402.7G -> 179.5G per 30 s), played-gameplay instructions -29% (391.6G -> 279.7G), loop iterations down ~1,400x, wait counts/durations unchanged, 30 fps frame pacing unchanged (max frametime 34.2 ms). Note: cpu-cycles PMU counts at full clock during WFE park on this SoC, so cycle-based profiles cannot see this change; measure with instructions retired.
This commit is contained in:
@@ -50,6 +50,7 @@ namespace rsx
|
||||
|
||||
u64 start = get_system_time();
|
||||
u64 last_check_val = start;
|
||||
u64 spin_budget = 0;
|
||||
|
||||
while (sema != arg)
|
||||
{
|
||||
@@ -92,8 +93,25 @@ namespace rsx
|
||||
|
||||
RSX_PROF_SCOPE(idle);
|
||||
|
||||
// Wait until the value changes or until 100us pass.
|
||||
utils::spin_on_cacheline_once(atomic_sema, sema, 100);
|
||||
#if defined(ARCH_ARM64)
|
||||
// The armed one-shot wait below does not park on every core: on Oryon
|
||||
// (Snapdragon 8 Elite class) WFE returns immediately while the exclusive
|
||||
// monitor is armed, so this loop ran at tens of millions of iterations per
|
||||
// second instead of waiting. Give the armed form a short window first - on
|
||||
// cores where it parks it keeps its instant wake-on-write, and where it
|
||||
// does not it acts as a brief spin that still catches short waits - then
|
||||
// fall back to the event-stream wait, which parks on both classes and
|
||||
// bounds wake latency at the event-stream period.
|
||||
if (++spin_budget > 500)
|
||||
{
|
||||
utils::wait_for_event();
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
// Wait until the value changes or until 100us pass.
|
||||
utils::spin_on_cacheline_once(atomic_sema, sema, 100);
|
||||
}
|
||||
}
|
||||
|
||||
RSX(ctx)->fifo_wake_delay();
|
||||
|
||||
Reference in New Issue
Block a user