diff --git a/PerfectNumbers.Core/Gpu/MersenneNumberDivisorByDivisorGpuTester.cs b/PerfectNumbers.Core/Gpu/MersenneNumberDivisorByDivisorGpuTester.cs index a820e13..5209fb7 100644 --- a/PerfectNumbers.Core/Gpu/MersenneNumberDivisorByDivisorGpuTester.cs +++ b/PerfectNumbers.Core/Gpu/MersenneNumberDivisorByDivisorGpuTester.cs @@ -27,17 +27,17 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester } private readonly ConcurrentDictionary, ArrayView>> _kernelCache = new(); - private readonly ConcurrentDictionary, ArrayView>> _kernelExponentCache = new(); - private readonly ConcurrentDictionary> _resourcePools = new(AcceleratorReferenceComparer.Instance); - private readonly ConcurrentDictionary, ArrayView>> _cycleKernelCache = new(); + private readonly ConcurrentDictionary, ArrayView>> _kernelExponentCache = new(); + private readonly ConcurrentDictionary> _resourcePools = new(AcceleratorReferenceComparer.Instance); + private readonly ConcurrentDictionary, ArrayView>> _cycleKernelCache = new(); private readonly ConcurrentBag _sessionPool = new(); private Action, ArrayView> GetKernel(Accelerator accelerator) => _kernelCache.GetOrAdd(accelerator, acc => acc.LoadAutoGroupedStreamKernel, ArrayView>(CheckKernel)); - private Action, ArrayView> GetKernelByPrimeExponent(Accelerator accelerator) => - _kernelExponentCache.GetOrAdd(accelerator, acc => acc.LoadAutoGroupedStreamKernel, ArrayView>(ComputePrimeExponentKernel)); - private Action, ArrayView> GetCycleKernel(Accelerator accelerator) => - _cycleKernelCache.GetOrAdd(accelerator, acc => acc.LoadAutoGroupedStreamKernel, ArrayView>(CheckPrimeCycleKernel)); + private Action, ArrayView> GetKernelByPrimeExponent(Accelerator accelerator) => + _kernelExponentCache.GetOrAdd(accelerator, acc => acc.LoadAutoGroupedStreamKernel, ArrayView>(ComputePrimeExponentKernel)); + private Action, ArrayView> GetCycleKernel(Accelerator accelerator) => + _cycleKernelCache.GetOrAdd(accelerator, acc => acc.LoadAutoGroupedStreamKernel, ArrayView>(CheckPrimeCycleKernel)); public int GpuBatchSize { @@ -340,253 +340,253 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester public sealed class DivisorScanSession : IDisposable { - private readonly MersenneNumberDivisorByDivisorGpuTester _owner; - private readonly GpuContextPool.GpuContextLease _lease; - private readonly Accelerator _accelerator; - private readonly Action, ArrayView> _kernel; - private readonly Action, ArrayView> _cycleKernel; - private MemoryBuffer1D _exponentsBuffer; - private MemoryBuffer1D _resultsBuffer; - private MemoryBuffer1D _cycleMaskBuffer; - private ulong[] _hostBuffer; - private ulong[] _primeBuffer; - private int[] _positionBuffer; - private byte[] _cycleMaskHost; - private int _capacity; - private bool _disposed; + private readonly MersenneNumberDivisorByDivisorGpuTester _owner; + private readonly GpuContextPool.GpuContextLease _lease; + private readonly Accelerator _accelerator; + private readonly Action, ArrayView> _kernel; + private readonly Action, ArrayView> _cycleKernel; + private MemoryBuffer1D _exponentsBuffer; + private MemoryBuffer1D _resultsBuffer; + private MemoryBuffer1D _cycleMaskBuffer; + private ulong[] _hostBuffer; + private ulong[] _primeBuffer; + private int[] _positionBuffer; + private byte[] _cycleMaskHost; + private int _capacity; + private bool _disposed; - internal DivisorScanSession(MersenneNumberDivisorByDivisorGpuTester owner) - { - _owner = owner; - _lease = GpuContextPool.RentPreferred(preferCpu: false); - _accelerator = _lease.Accelerator; - _kernel = owner.GetKernelByPrimeExponent(_accelerator); - _cycleKernel = owner.GetCycleKernel(_accelerator); - _capacity = Math.Max(1, owner._gpuBatchSize); - _exponentsBuffer = _accelerator.Allocate1D(_capacity); - _resultsBuffer = _accelerator.Allocate1D(_capacity); - _cycleMaskBuffer = _accelerator.Allocate1D(_capacity); - _hostBuffer = ArrayPool.Shared.Rent(_capacity); - _primeBuffer = ArrayPool.Shared.Rent(_capacity); - _positionBuffer = ArrayPool.Shared.Rent(_capacity); - _cycleMaskHost = ArrayPool.Shared.Rent(_capacity); - } + internal DivisorScanSession(MersenneNumberDivisorByDivisorGpuTester owner) + { + _owner = owner; + _lease = GpuContextPool.RentPreferred(preferCpu: false); + _accelerator = _lease.Accelerator; + _kernel = owner.GetKernelByPrimeExponent(_accelerator); + _cycleKernel = owner.GetCycleKernel(_accelerator); + _capacity = Math.Max(1, owner._gpuBatchSize); + _exponentsBuffer = _accelerator.Allocate1D(_capacity); + _resultsBuffer = _accelerator.Allocate1D(_capacity); + _cycleMaskBuffer = _accelerator.Allocate1D(_capacity); + _hostBuffer = ArrayPool.Shared.Rent(_capacity); + _primeBuffer = ArrayPool.Shared.Rent(_capacity); + _positionBuffer = ArrayPool.Shared.Rent(_capacity); + _cycleMaskHost = ArrayPool.Shared.Rent(_capacity); + } - internal void Reset() - { - _disposed = false; + internal void Reset() + { + _disposed = false; } private void EnsureCapacity(int requiredCapacity) { - if (requiredCapacity <= _capacity) - { - return; - } + if (requiredCapacity <= _capacity) + { + return; + } - _exponentsBuffer.Dispose(); - _resultsBuffer.Dispose(); - _cycleMaskBuffer.Dispose(); - ArrayPool.Shared.Return(_hostBuffer, clearArray: false); - ArrayPool.Shared.Return(_primeBuffer, clearArray: false); - ArrayPool.Shared.Return(_positionBuffer, clearArray: false); - ArrayPool.Shared.Return(_cycleMaskHost, clearArray: false); + _exponentsBuffer.Dispose(); + _resultsBuffer.Dispose(); + _cycleMaskBuffer.Dispose(); + ArrayPool.Shared.Return(_hostBuffer, clearArray: false); + ArrayPool.Shared.Return(_primeBuffer, clearArray: false); + ArrayPool.Shared.Return(_positionBuffer, clearArray: false); + ArrayPool.Shared.Return(_cycleMaskHost, clearArray: false); - _capacity = requiredCapacity; - _exponentsBuffer = _accelerator.Allocate1D(_capacity); - _resultsBuffer = _accelerator.Allocate1D(_capacity); - _cycleMaskBuffer = _accelerator.Allocate1D(_capacity); - _hostBuffer = ArrayPool.Shared.Rent(_capacity); - _primeBuffer = ArrayPool.Shared.Rent(_capacity); - _positionBuffer = ArrayPool.Shared.Rent(_capacity); - _cycleMaskHost = ArrayPool.Shared.Rent(_capacity); - } + _capacity = requiredCapacity; + _exponentsBuffer = _accelerator.Allocate1D(_capacity); + _resultsBuffer = _accelerator.Allocate1D(_capacity); + _cycleMaskBuffer = _accelerator.Allocate1D(_capacity); + _hostBuffer = ArrayPool.Shared.Rent(_capacity); + _primeBuffer = ArrayPool.Shared.Rent(_capacity); + _positionBuffer = ArrayPool.Shared.Rent(_capacity); + _cycleMaskHost = ArrayPool.Shared.Rent(_capacity); + } - public void CheckDivisor(ulong divisor, ulong divisorCycle, ReadOnlySpan primes, Span hits) - { - if (_disposed) - { - throw new ObjectDisposedException(nameof(DivisorScanSession)); - } + public void CheckDivisor(ulong divisor, ulong divisorCycle, ReadOnlySpan primes, Span hits) + { + if (_disposed) + { + throw new ObjectDisposedException(nameof(DivisorScanSession)); + } - int primesLength = primes.Length; - if (primesLength == 0) - { - return; - } + int primesLength = primes.Length; + if (primesLength == 0) + { + return; + } - MersenneNumberDivisorByDivisorGpuTester owner = _owner; - int gpuBatchSize = owner._gpuBatchSize; - EnsureCapacity(gpuBatchSize); + MersenneNumberDivisorByDivisorGpuTester owner = _owner; + int gpuBatchSize = owner._gpuBatchSize; + EnsureCapacity(gpuBatchSize); - MontgomeryDivisorData divisorData = CreateMontgomeryDivisorData(divisor); - ulong modulus = divisorData.Modulus; - if (modulus <= 1UL || (modulus & 1UL) == 0UL) - { - return; - } + MontgomeryDivisorData divisorData = CreateMontgomeryDivisorData(divisor); + ulong modulus = divisorData.Modulus; + if (modulus <= 1UL || (modulus & 1UL) == 0UL) + { + return; + } - bool cycleEnabled = owner._useDivisorCycles && divisorCycle != 0UL; + bool cycleEnabled = owner._useDivisorCycles && divisorCycle != 0UL; - Accelerator accelerator = _accelerator; - Action, ArrayView> kernel = _kernel; - Action, ArrayView> cycleKernel = _cycleKernel; - ArrayView1D exponentsView = _exponentsBuffer.View; - ArrayView1D resultsView = _resultsBuffer.View; - ArrayView1D cycleMaskViewFull = _cycleMaskBuffer.View; + Accelerator accelerator = _accelerator; + Action, ArrayView> kernel = _kernel; + Action, ArrayView> cycleKernel = _cycleKernel; + ArrayView1D exponentsView = _exponentsBuffer.View; + ArrayView1D resultsView = _resultsBuffer.View; + ArrayView1D cycleMaskViewFull = _cycleMaskBuffer.View; - int offset = 0; - Span hostSpan = _hostBuffer.AsSpan(); - Span primeSpan = _primeBuffer.AsSpan(); - Span positionSpan = _positionBuffer.AsSpan(); - bool hasPreviousResidue = false; - ulong previousResidue = 0UL; - ulong previousPrime = 0UL; + int offset = 0; + Span hostSpan = _hostBuffer.AsSpan(); + Span primeSpan = _primeBuffer.AsSpan(); + Span positionSpan = _positionBuffer.AsSpan(); + bool hasPreviousResidue = false; + ulong previousResidue = 0UL; + ulong previousPrime = 0UL; - while (offset < primesLength) - { - int batchSize = Math.Min(gpuBatchSize, primesLength - offset); - ReadOnlySpan primesSlice = primes.Slice(offset, batchSize); - Span hitsSlice = hits.Slice(offset, batchSize); + while (offset < primesLength) + { + int batchSize = Math.Min(gpuBatchSize, primesLength - offset); + ReadOnlySpan primesSlice = primes.Slice(offset, batchSize); + Span hitsSlice = hits.Slice(offset, batchSize); - int computeCount = 0; - Span cycleMaskSpan = default; + int computeCount = 0; + Span cycleMaskSpan = default; - if (cycleEnabled) - { - cycleMaskSpan = _cycleMaskHost.AsSpan(0, batchSize); - ArrayView1D primeInputView = _resultsBuffer.View.SubView(0, batchSize); - primeInputView.CopyFromCPU(ref MemoryMarshal.GetReference(primesSlice), batchSize); - ArrayView1D cycleMaskView = cycleMaskViewFull.SubView(0, batchSize); - cycleKernel(batchSize, divisorCycle, primeInputView, cycleMaskView); - accelerator.Synchronize(); - cycleMaskView.CopyToCPU(ref MemoryMarshal.GetReference(cycleMaskSpan), batchSize); - } + if (cycleEnabled) + { + cycleMaskSpan = _cycleMaskHost.AsSpan(0, batchSize); + ArrayView1D primeInputView = _resultsBuffer.View.SubView(0, batchSize); + primeInputView.CopyFromCPU(ref MemoryMarshal.GetReference(primesSlice), batchSize); + ArrayView1D cycleMaskView = cycleMaskViewFull.SubView(0, batchSize); + cycleKernel(batchSize, divisorCycle, primeInputView, cycleMaskView); + accelerator.Synchronize(); + cycleMaskView.CopyToCPU(ref MemoryMarshal.GetReference(cycleMaskSpan), batchSize); + } - for (int i = 0; i < batchSize; i++) - { - if (cycleEnabled && cycleMaskSpan[i] == 0) - { - hitsSlice[i] = 0; - continue; - } + for (int i = 0; i < batchSize; i++) + { + if (cycleEnabled && cycleMaskSpan[i] == 0) + { + hitsSlice[i] = 0; + continue; + } - ulong prime = primesSlice[i]; - primeSpan[computeCount] = prime; - positionSpan[computeCount] = i; - computeCount++; - } + ulong prime = primesSlice[i]; + primeSpan[computeCount] = prime; + positionSpan[computeCount] = i; + computeCount++; + } - if (computeCount > 0) - { - Span exponentSlice = hostSpan.Slice(0, computeCount); - ulong currentPrime = hasPreviousResidue ? previousPrime : 0UL; - bool hasDeltaSource = hasPreviousResidue; + if (computeCount > 0) + { + Span exponentSlice = hostSpan[..computeCount]; + ulong currentPrime = hasPreviousResidue ? previousPrime : 0UL; + bool hasDeltaSource = hasPreviousResidue; - for (int i = 0; i < computeCount; i++) - { - ulong prime = primeSpan[i]; - if (hasDeltaSource) - { - exponentSlice[i] = prime - currentPrime; - } - else - { - exponentSlice[i] = prime; - hasDeltaSource = true; - } + for (int i = 0; i < computeCount; i++) + { + ulong prime = primeSpan[i]; + if (hasDeltaSource) + { + exponentSlice[i] = prime - currentPrime; + } + else + { + exponentSlice[i] = prime; + hasDeltaSource = true; + } - currentPrime = prime; - } + currentPrime = prime; + } - ArrayView1D exponentView = exponentsView.SubView(0, computeCount); - exponentView.CopyFromCPU(ref MemoryMarshal.GetReference(exponentSlice), computeCount); - ArrayView1D resultView = resultsView.SubView(0, computeCount); - kernel(computeCount, divisorData, exponentView, resultView); - accelerator.Synchronize(); - resultView.CopyToCPU(ref MemoryMarshal.GetReference(exponentSlice), computeCount); + ArrayView1D exponentView = exponentsView.SubView(0, computeCount); + exponentView.CopyFromCPU(ref MemoryMarshal.GetReference(exponentSlice), computeCount); + ArrayView1D resultView = resultsView.SubView(0, computeCount); + kernel(computeCount, divisorData, exponentView, resultView); + accelerator.Synchronize(); + resultView.CopyToCPU(ref MemoryMarshal.GetReference(exponentSlice), computeCount); - ulong residueAccumulator = previousResidue; - ulong lastPrime = previousPrime; - bool hasAccumulator = hasPreviousResidue; + ulong residueAccumulator = previousResidue; + ulong lastPrime = previousPrime; + bool hasAccumulator = hasPreviousResidue; - for (int i = 0; i < computeCount; i++) - { - int position = positionSpan[i]; - ulong stepResidue = exponentSlice[i]; - ulong prime = primeSpan[i]; - ulong residue = hasAccumulator ? MultiplyMod(residueAccumulator, stepResidue, modulus) : stepResidue; - hitsSlice[position] = residue == 1UL ? (byte)1 : (byte)0; - exponentSlice[i] = residue; - residueAccumulator = residue; - lastPrime = prime; - hasAccumulator = true; - } + for (int i = 0; i < computeCount; i++) + { + int position = positionSpan[i]; + ulong stepResidue = exponentSlice[i]; + ulong prime = primeSpan[i]; + ulong residue = hasAccumulator ? MultiplyMod(residueAccumulator, stepResidue, modulus) : stepResidue; + hitsSlice[position] = residue == 1UL ? (byte)1 : (byte)0; + exponentSlice[i] = residue; + residueAccumulator = residue; + lastPrime = prime; + hasAccumulator = true; + } - if (hasAccumulator) - { - previousResidue = residueAccumulator; - previousPrime = lastPrime; - hasPreviousResidue = true; - } - } + if (hasAccumulator) + { + previousResidue = residueAccumulator; + previousPrime = lastPrime; + hasPreviousResidue = true; + } + } - offset += batchSize; - } - } + offset += batchSize; + } + } - public void Dispose() - { - if (_disposed) - { - return; - } + public void Dispose() + { + if (_disposed) + { + return; + } - _disposed = true; - _owner.ReturnSession(this); - } + _disposed = true; + _owner.ReturnSession(this); + } - private static ulong MultiplyMod(ulong left, ulong right, ulong modulus) - { - if (modulus == 0UL) - { - return 0UL; - } + private static ulong MultiplyMod(ulong left, ulong right, ulong modulus) + { + if (modulus == 0UL) + { + return 0UL; + } - UInt128 product = (UInt128)left * right; - return (ulong)(product % modulus); - } + UInt128 product = (UInt128)left * right; + return (ulong)(product % modulus); + } - } + } internal void ReturnSession(DivisorScanSession session) { _sessionPool.Add(session); } - private static void CheckPrimeCycleKernel(Index1D index, ulong cycle, ArrayView primes, ArrayView mask) - { - if (cycle == 0UL) - { - mask[index] = 1; - return; - } + private static void CheckPrimeCycleKernel(Index1D index, ulong cycle, ArrayView primes, ArrayView mask) + { + if (cycle == 0UL) + { + mask[index] = 1; + return; + } - mask[index] = primes[index] % cycle == 0UL ? (byte)1 : (byte)0; - } + mask[index] = primes[index] % cycle == 0UL ? (byte)1 : (byte)0; + } - private static void ComputePrimeExponentKernel(Index1D index, MontgomeryDivisorData divisor, ArrayView exponents, ArrayView results) - { - ulong modulus = divisor.Modulus; - if (modulus <= 1UL || (modulus & 1UL) == 0UL) - { - results[index] = 0UL; - return; - } + private static void ComputePrimeExponentKernel(Index1D index, MontgomeryDivisorData divisor, ArrayView exponents, ArrayView results) + { + ulong modulus = divisor.Modulus; + if (modulus <= 1UL || (modulus & 1UL) == 0UL) + { + results[index] = 0UL; + return; + } - ulong exponent = exponents[index]; - results[index] = exponent.Pow2MontgomeryMod(divisor); - } + ulong exponent = exponents[index]; + results[index] = exponent.Pow2MontgomeryMod(divisor); + } private static MontgomeryDivisorData CreateMontgomeryDivisorData(ulong modulus) {