From 1be668e68a1937f2af239e2707ab914286018892 Mon Sep 17 00:00:00 2001 From: riperiperi <rhy3756547@hotmail.com> Date: Thu, 30 Nov 2023 10:39:42 -0800 Subject: HLE: Add OS-specific precise sleep methods to reduce spinwaiting (#5948) * feat: add nanosleep for linux and macos * Add Windows 0.5ms sleep - Imprecise waits for longer waits with clock alignment - 1/4 the spin time on vsync timer * Remove old experiment * Fix event leak * Tweaking for MacOS * Linux tweaks, nanosleep vsync improvement * Fix overbias * Cleanup * Fix realignment * Add some docs and some cleanup NanosleepPool needs more, Nanosleep has some benchmark code that needs removed. * Rename "Microsleep" to "PreciseSleep" Might have been confused with "microseconds", which no measurement is performed in. * Remove nanosleep measurement * Remove unused debug logging * Nanosleep Pool Documentation * More cleanup * Whitespace * Formatting * Address Feedback * Allow SleepUntilTimePoint to take EventWaitHandle * Remove `_chrono` stopwatch in SurfaceFlinger * Move spinwaiting logic to PreciseSleepHelper Technically, these achieve different things, but having them here makes them easier to reuse or tune. --- src/Ryujinx.HLE/HOS/Kernel/Common/KTimeManager.cs | 39 ++++++----------------- 1 file changed, 10 insertions(+), 29 deletions(-) (limited to 'src/Ryujinx.HLE/HOS/Kernel/Common/KTimeManager.cs') diff --git a/src/Ryujinx.HLE/HOS/Kernel/Common/KTimeManager.cs b/src/Ryujinx.HLE/HOS/Kernel/Common/KTimeManager.cs index 499bc2c6..3c5fa067 100644 --- a/src/Ryujinx.HLE/HOS/Kernel/Common/KTimeManager.cs +++ b/src/Ryujinx.HLE/HOS/Kernel/Common/KTimeManager.cs @@ -1,4 +1,5 @@ using Ryujinx.Common; +using Ryujinx.Common.PreciseSleep; using System; using System.Collections.Generic; using System.Threading; @@ -23,7 +24,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Common private readonly KernelContext _context; private readonly List<WaitingObject> _waitingObjects; - private AutoResetEvent _waitEvent; + private IPreciseSleepEvent _waitEvent; private bool _keepRunning; private long _enforceWakeupFromSpinWait; @@ -54,6 +55,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Common timePoint = long.MaxValue; } + timePoint = _waitEvent.AdjustTimePoint(timePoint, timeout); + lock (_context.CriticalSection.Lock) { _waitingObjects.Add(new WaitingObject(schedulerObj, timePoint)); @@ -64,7 +67,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Common } } - _waitEvent.Set(); + _waitEvent.Signal(); } public void UnscheduleFutureInvocation(IKFutureSchedulerObject schedulerObj) @@ -83,10 +86,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Common private void WaitAndCheckScheduledObjects() { - SpinWait spinWait = new(); WaitingObject next; - using (_waitEvent = new AutoResetEvent(false)) + using (_waitEvent = PreciseSleepHelper.CreateEvent()) { while (_keepRunning) { @@ -103,30 +105,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Common if (next.TimePoint > timePoint) { - long ms = Math.Min((next.TimePoint - timePoint) / PerformanceCounter.TicksPerMillisecond, int.MaxValue); - - if (ms > 0) - { - _waitEvent.WaitOne((int)ms); - } - else + if (!_waitEvent.SleepUntil(next.TimePoint)) { - while (Interlocked.Read(ref _enforceWakeupFromSpinWait) != 1 && PerformanceCounter.ElapsedTicks < next.TimePoint) - { - // Our time is close - don't let SpinWait go off and potentially Thread.Sleep(). - if (spinWait.NextSpinWillYield) - { - Thread.Yield(); - - spinWait.Reset(); - } - else - { - spinWait.SpinOnce(); - } - } - - spinWait.Reset(); + PreciseSleepHelper.SpinWaitUntilTimePoint(next.TimePoint, ref _enforceWakeupFromSpinWait); } } @@ -145,7 +126,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Common } else { - _waitEvent.WaitOne(); + _waitEvent.Sleep(); } } } @@ -212,7 +193,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Common public void Dispose() { _keepRunning = false; - _waitEvent?.Set(); + _waitEvent?.Signal(); } } } -- cgit v1.2.3-70-g09d2