Gate GPU by-divisor scans to a single accelerator

This commit is contained in:
Marek Lemańczyk committed 2025-10-25 05:00:54 +02:00
1 parent 6b1c2d0665
commit 3735a1cf0f
1 file changed
+50 -2
@@ -26,6 +26,11 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
private readonly ConcurrentDictionary<Accelerator, Action<Index1D, ArrayView<GpuDivisorPartialData>, ArrayView<int>, ArrayView<int>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>, ArrayView<int>>> _kernelCache = new(AcceleratorReferenceComparer.Instance); private readonly ConcurrentDictionary<Accelerator, Action<Index1D, ArrayView<GpuDivisorPartialData>, ArrayView<int>, ArrayView<int>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>, ArrayView<int>>> _kernelCache = new(AcceleratorReferenceComparer.Instance);
private readonly ConcurrentDictionary<Accelerator, ConcurrentBag<BatchResources>> _resourcePools = new(AcceleratorReferenceComparer.Instance); private readonly ConcurrentDictionary<Accelerator, ConcurrentBag<BatchResources>> _resourcePools = new(AcceleratorReferenceComparer.Instance);
private readonly ConcurrentBag<GpuContextPool.GpuContextLease> _acceleratorPool = new(); private readonly ConcurrentBag<GpuContextPool.GpuContextLease> _acceleratorPool = new();
private readonly SemaphoreSlim _acceleratorAvailable = new(0);
private int _createdAccelerators;
// Limit GPU context concurrency to avoid replicating the large batch buffers across thousands of worker threads.
private int _acceleratorLimit = 1;
private int _waitingAcceleratorCount;
private readonly ConcurrentBag<DivisorScanSession> _sessionPool = new(); private readonly ConcurrentBag<DivisorScanSession> _sessionPool = new();
private Action<Index1D, ArrayView<GpuDivisorPartialData>, ArrayView<int>, ArrayView<int>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>, ArrayView<int>> GetKernel(Accelerator accelerator) => private Action<Index1D, ArrayView<GpuDivisorPartialData>, ArrayView<int>, ArrayView<int>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>, ArrayView<int>> GetKernel(Accelerator accelerator) =>
@@ -678,16 +683,59 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
} }
private GpuContextPool.GpuContextLease RentAccelerator() private GpuContextPool.GpuContextLease RentAccelerator()
{
while (true)
{ {
if (_acceleratorPool.TryTake(out var lease)) if (_acceleratorPool.TryTake(out var lease))
{ {
return lease; return lease;
} }
return GpuContextPool.RentPreferred(preferCpu: false); if (TryCreateAccelerator(out lease))
{
return lease;
} }
private void ReturnAccelerator(GpuContextPool.GpuContextLease lease) => _acceleratorPool.Add(lease); Interlocked.Increment(ref _waitingAcceleratorCount);
try
{
_acceleratorAvailable.Wait();
}
finally
{
Interlocked.Decrement(ref _waitingAcceleratorCount);
}
}
}
private bool TryCreateAccelerator(out GpuContextPool.GpuContextLease lease)
{
while (true)
{
int created = Volatile.Read(ref _createdAccelerators);
int limit = Volatile.Read(ref _acceleratorLimit);
if (created >= limit)
{
lease = default;
return false;
}
if (Interlocked.CompareExchange(ref _createdAccelerators, created + 1, created) == created)
{
lease = GpuContextPool.RentPreferred(preferCpu: false);
return true;
}
}
}
private void ReturnAccelerator(GpuContextPool.GpuContextLease lease)
{
_acceleratorPool.Add(lease);
if (Volatile.Read(ref _waitingAcceleratorCount) > 0)
{
_acceleratorAvailable.Release();
}
}
private BatchResources RentBatchResources(Accelerator accelerator, int capacity) private BatchResources RentBatchResources(Accelerator accelerator, int capacity)
{ {