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.
This commit is contained in:
parent
21cd4c0c00
commit
1be668e68a
10 changed files with 1000 additions and 49 deletions
|
@ -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)
|
||||
if (!_waitEvent.SleepUntil(next.TimePoint))
|
||||
{
|
||||
_waitEvent.WaitOne((int)ms);
|
||||
}
|
||||
else
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue