SemaphoreSlim replaced with PollingSemaphore.

This commit is contained in:
mlemanczyk committed 2025-12-12 03:41:13 +01:00
1 parent 471f9ac6cf
commit 15bcde1776
4 files changed
+57 -51

No files matched your search

+47 -46
View File
@@ -1,58 +1,59 @@
using System.Runtime.CompilerServices;
namespace PerfectNumbers.Core.Gpu;
public static class GpuWorkLimiter
{
private static SemaphoreSlim _semaphore = new(1, int.MaxValue);
private static readonly object _lock = new();
private static int _currentLimit = 1;
private static readonly TimeSpan _pauseBetweenChecks = TimeSpan.FromSeconds(30);
private static PollingSemaphore _semaphore = new(int.MaxValue, _pauseBetweenChecks, 1);
private static readonly object _lock = new();
private static int _currentLimit = 1;
public static Lease Acquire()
{
// TODO: Replace the per-call Lease allocation with the pooled struct-based guard from the
// GpuLimiterThroughputBenchmarks so limiter acquisition does not allocate when we enter the
// GPU scanning hot path.
var sem = _semaphore;
sem.Wait();
return new Lease(sem);
}
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static Lease Acquire()
{
// TODO: Replace the per-call Lease allocation with the pooled struct-based guard from the
// GpuLimiterThroughputBenchmarks so limiter acquisition does not allocate when we enter the
// GPU scanning hot path.
var sem = _semaphore;
sem.Wait();
return new Lease(sem);
}
public static void SetLimit(int value)
{
if (value < 1)
{
value = 1;
}
public static void SetLimit(int value)
{
if (value < 1)
{
value = 1;
}
lock (_lock)
{
if (value == _currentLimit)
{
return;
}
lock (_lock)
{
if (value == _currentLimit)
{
return;
}
// Swap to a new semaphore for the new limit. We intentionally
// do not dispose the old semaphore to avoid releasing handles
// that may still be in use by existing Lease instances.
// TODO: Consolidate with GpuPrimeWorkLimiter so both limiters share a pooled SemaphoreSlim and avoid rebuilding the
// limiter state whenever limits are adjusted from the CLI.
_semaphore = new SemaphoreSlim(value, value);
_currentLimit = value;
}
}
// Swap to a new semaphore for the new limit. We intentionally
// do not dispose the old semaphore to avoid releasing handles
// that may still be in use by existing Lease instances.
// TODO: Consolidate with GpuPrimeWorkLimiter so both limiters share a pooled SemaphoreSlim and avoid rebuilding the
// limiter state whenever limits are adjusted from the CLI.
_semaphore = new PollingSemaphore(value, _pauseBetweenChecks, 1);
_currentLimit = value;
}
}
public sealed class Lease
{
private readonly SemaphoreSlim _sem;
[method: MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public readonly struct Lease(PollingSemaphore sem)
{
private readonly PollingSemaphore _sem = sem;
internal Lease(SemaphoreSlim sem)
{
_sem = sem;
}
public void Dispose()
{
_sem.Release();
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public void Dispose()
{
_sem.Release();
}
}
}