GpuPrimeWorkLimiter.Acquire() / .Release() removed to save time on the hot-path with billions of calls. We'll rely on AcceleratorStreamPool limits and synchronization.

This commit is contained in:
mlemanczyk committed 2025-11-13 17:52:13 +01:00
1 parent 1552e10ff0
commit 0d2a88c45f
17 files changed
+100 -116

No files matched your search

@@ -365,7 +365,7 @@ public class GpuKernelCompilationTests
{ {
stream.Synchronize(); stream.Synchronize();
stream.Dispose(); stream.Dispose();
GpuPrimeWorkLimiter.Release(); // GpuPrimeWorkLimiter.Release();
} }
stream = accelerator.CreateStream(); stream = accelerator.CreateStream();
@@ -383,7 +383,7 @@ public class GpuKernelCompilationTests
{ {
stream.Synchronize(); stream.Synchronize();
stream.Dispose(); stream.Dispose();
GpuPrimeWorkLimiter.Release(); // GpuPrimeWorkLimiter.Release();
} }
} }
} }
+9 -13
View File
@@ -41,8 +41,9 @@ public sealed class DivisorCycleCache
private DivisorCycleCache(int divisorCyclesBatchSize) private DivisorCycleCache(int divisorCyclesBatchSize)
{ {
_divisorCyclesBatchSize = Math.Max(1, divisorCyclesBatchSize); _divisorCyclesBatchSize = Math.Max(1, divisorCyclesBatchSize);
_accelerator = SharedGpuContext.Device.CreateAccelerator(SharedGpuContext.Context); var accelerator = AcceleratorPool.Shared.Rent();
_gpuKernel = LoadKernel(_accelerator); _accelerator = accelerator;
_gpuKernel = LoadKernel(accelerator);
_snapshot = MersenneDivisorCycles.Shared.ExportSmallCyclesSnapshot(); _snapshot = MersenneDivisorCycles.Shared.ExportSmallCyclesSnapshot();
} }
@@ -83,7 +84,6 @@ public sealed class DivisorCycleCache
throw new InvalidDataException($"Divisor cycle is missing for {divisor}"); throw new InvalidDataException($"Divisor cycle is missing for {divisor}");
} }
// ObserveCycleCacheDivisor(divisor);
return cached; return cached;
} }
@@ -118,7 +118,6 @@ public sealed class DivisorCycleCache
throw new InvalidDataException($"Divisor cycle is missing for {divisor}"); throw new InvalidDataException($"Divisor cycle is missing for {divisor}");
} }
// ObserveCycleCacheDivisor(divisor);
cycles[i] = cached; cycles[i] = cached;
} }
else else
@@ -261,15 +260,12 @@ public sealed class DivisorCycleCache
} }
Accelerator accelerator = _accelerator; Accelerator accelerator = _accelerator;
// lock(accelerator)
{
divisorBuffer = accelerator.Allocate1D<ulong>(requiredCapacity); divisorBuffer = accelerator.Allocate1D<ulong>(requiredCapacity);
powBuffer = accelerator.Allocate1D<ulong>(requiredCapacity); powBuffer = accelerator.Allocate1D<ulong>(requiredCapacity);
orderBuffer = accelerator.Allocate1D<ulong>(requiredCapacity); orderBuffer = accelerator.Allocate1D<ulong>(requiredCapacity);
resultBuffer = accelerator.Allocate1D<ulong>(requiredCapacity); resultBuffer = accelerator.Allocate1D<ulong>(requiredCapacity);
statusBuffer = accelerator.Allocate1D<byte>(requiredCapacity); statusBuffer = accelerator.Allocate1D<byte>(requiredCapacity);
} }
}
private void ComputeCyclesGpuCore(ReadOnlySpan<ulong> divisors, Span<ulong> destination) private void ComputeCyclesGpuCore(ReadOnlySpan<ulong> divisors, Span<ulong> destination)
{ {
@@ -312,8 +308,10 @@ public sealed class DivisorCycleCache
statusSpan[i] = ByteZero; statusSpan[i] = ByteZero;
} }
GpuPrimeWorkLimiter.Acquire(); // GpuPrimeWorkLimiter.Acquire();
var stream = AcceleratorStreamPool.Rent(_accelerator);// accelerator.CreateStream(); int pending;
var kernel = _gpuKernel;
var stream = AcceleratorStreamPool.Rent(_accelerator);
divisorBuffer!.View.CopyFromCPU(stream, divisors); divisorBuffer!.View.CopyFromCPU(stream, divisors);
powBuffer!.View.CopyFromCPU(stream, powSpan); powBuffer!.View.CopyFromCPU(stream, powSpan);
@@ -321,8 +319,6 @@ public sealed class DivisorCycleCache
resultBuffer!.View.CopyFromCPU(stream, resultSpan); resultBuffer!.View.CopyFromCPU(stream, resultSpan);
statusBuffer!.View.CopyFromCPU(stream, statusSpan); statusBuffer!.View.CopyFromCPU(stream, statusSpan);
int pending;
var kernel = _gpuKernel;
do do
{ {
kernel(stream, length, _divisorCyclesBatchSize, divisorBuffer.View, powBuffer.View, orderBuffer.View, resultBuffer.View, statusBuffer.View); kernel(stream, length, _divisorCyclesBatchSize, divisorBuffer.View, powBuffer.View, orderBuffer.View, resultBuffer.View, statusBuffer.View);
@@ -341,7 +337,7 @@ public sealed class DivisorCycleCache
} }
while (pending > 0); while (pending > 0);
resultBuffer.View.CopyToCPU(stream,resultSpan); resultBuffer.View.CopyToCPU(stream, resultSpan);
stream.Synchronize(); stream.Synchronize();
AcceleratorStreamPool.Return(stream); AcceleratorStreamPool.Return(stream);
@@ -354,7 +350,7 @@ public sealed class DivisorCycleCache
ThreadStaticPools.BytePool.Return(rentedStatus!, clearArray: false); ThreadStaticPools.BytePool.Return(rentedStatus!, clearArray: false);
} }
GpuPrimeWorkLimiter.Release(); // GpuPrimeWorkLimiter.Release();
} }
private static Action<AcceleratorStream, Index1D, int, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<byte, Stride1D.Dense>> LoadKernel(Accelerator accelerator) private static Action<AcceleratorStream, Index1D, int, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<byte, Stride1D.Dense>> LoadKernel(Accelerator accelerator)
+2 -2
View File
@@ -280,13 +280,13 @@ public class GpuKernelPool
/// <param name="action">Action to run with (Accelerator, Stream).</param> /// <param name="action">Action to run with (Accelerator, Stream).</param>
public static void Run(Action<Accelerator, AcceleratorStream> action) public static void Run(Action<Accelerator, AcceleratorStream> action)
{ {
GpuPrimeWorkLimiter.Acquire(); // GpuPrimeWorkLimiter.Acquire();
var accelerator = SharedGpuContext.CreateAccelerator(); var accelerator = SharedGpuContext.CreateAccelerator();
var stream = accelerator.CreateStream(); var stream = accelerator.CreateStream();
action(accelerator, stream); action(accelerator, stream);
stream.Synchronize(); stream.Synchronize();
stream.Dispose(); stream.Dispose();
accelerator.Dispose(); accelerator.Dispose();
GpuPrimeWorkLimiter.Release(); // GpuPrimeWorkLimiter.Release();
} }
} }
@@ -103,7 +103,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
ulong processedCount; ulong processedCount;
ulong lastProcessed; ulong lastProcessed;
GpuPrimeWorkLimiter.Acquire(); // GpuPrimeWorkLimiter();
var accelerator = AcceleratorPool.Shared.Rent(); var accelerator = AcceleratorPool.Shared.Rent();
var stream = accelerator.CreateStream(); var stream = accelerator.CreateStream();
@@ -137,7 +137,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
stream.Dispose(); stream.Dispose();
ReturnBatchResources(resources); ReturnBatchResources(resources);
// Monitor.Exit(gpuLease.ExecutionLock); // Monitor.Exit(gpuLease.ExecutionLock);
GpuPrimeWorkLimiter.Release(); // GpuPrimeWorkLimiter.Release();
if (composite) if (composite)
{ {
@@ -509,7 +509,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
internal DivisorScanSession(MersenneNumberDivisorByDivisorGpuTester owner) internal DivisorScanSession(MersenneNumberDivisorByDivisorGpuTester owner)
{ {
_owner = owner; _owner = owner;
GpuPrimeWorkLimiter.Acquire(); // GpuPrimeWorkLimiter.Acquire();
Accelerator accelerator = AcceleratorPool.Shared.Rent(); Accelerator accelerator = AcceleratorPool.Shared.Rent();
_accelerator = accelerator; _accelerator = accelerator;
_stream = accelerator.CreateStream(); _stream = accelerator.CreateStream();
@@ -16,7 +16,7 @@ public class MersenneNumberIncrementalGpuTester(GpuKernelType kernelType, bool u
{ {
throw new NotImplementedException($"GPU incremental scanning requires the device cycle heuristics implementation (kernel: {_kernelType}, GPU order: {_useGpuOrder})."); throw new NotImplementedException($"GPU incremental scanning requires the device cycle heuristics implementation (kernel: {_kernelType}, GPU order: {_useGpuOrder}).");
GpuPrimeWorkLimiter.Acquire(); // GpuPrimeWorkLimiter.Acquire();
var accelerator = AcceleratorPool.Shared.Rent(); var accelerator = AcceleratorPool.Shared.Rent();
var stream = accelerator.CreateStream(); var stream = accelerator.CreateStream();
int batchSize = GpuConstants.ScanBatchSize; // large batch improves GPU occupancy int batchSize = GpuConstants.ScanBatchSize; // large batch improves GPU occupancy
@@ -125,6 +125,6 @@ public class MersenneNumberIncrementalGpuTester(GpuKernelType kernelType, bool u
stream.Dispose(); stream.Dispose();
ulongPool.Return(orderArray); ulongPool.Return(orderArray);
orderBuffer.Dispose(); orderBuffer.Dispose();
GpuPrimeWorkLimiter.Release(); // GpuPrimeWorkLimiter.Release();
} }
} }
@@ -159,7 +159,7 @@ public class MersenneNumberLucasLehmerGpuTester
} }
else else
{ {
GpuPrimeWorkLimiter.Acquire(); // GpuPrimeWorkLimiter.Acquire();
var accelerator = AcceleratorPool.Shared.Rent(); var accelerator = AcceleratorPool.Shared.Rent();
var stream = accelerator.CreateStream(); var stream = accelerator.CreateStream();
var modulus = new GpuUInt128(((UInt128)1 << (int)exponent) - 1UL); // TODO: Cache these Mersenne moduli per exponent so LL GPU runs skip rebuilding them every launch. var modulus = new GpuUInt128(((UInt128)1 << (int)exponent) - 1UL); // TODO: Cache these Mersenne moduli per exponent so LL GPU runs skip rebuilding them every launch.
@@ -173,7 +173,7 @@ public class MersenneNumberLucasLehmerGpuTester
stream.Dispose(); stream.Dispose();
} }
GpuPrimeWorkLimiter.Release(); // GpuPrimeWorkLimiter.Release();
return result; return result;
} }
@@ -9,7 +9,7 @@ public class MersenneNumberOrderGpuTester(GpuKernelType kernelType, bool useGpuO
public void Scan(ulong exponent, UInt128 twoP, LastDigit lastDigit, UInt128 maxK, ref bool isPrime) public void Scan(ulong exponent, UInt128 twoP, LastDigit lastDigit, UInt128 maxK, ref bool isPrime)
{ {
GpuPrimeWorkLimiter.Acquire(); // GpuPrimeWorkLimiter.Acquire();
// var accelerator = SharedGpuContext.Accelerator; // var accelerator = SharedGpuContext.Accelerator;
var accelerator = AcceleratorPool.Shared.Rent(); var accelerator = AcceleratorPool.Shared.Rent();
var stream = accelerator.CreateStream(); var stream = accelerator.CreateStream();
@@ -71,6 +71,6 @@ public class MersenneNumberOrderGpuTester(GpuKernelType kernelType, bool useGpuO
stream.Dispose(); stream.Dispose();
foundBuffer.Dispose(); foundBuffer.Dispose();
GpuPrimeWorkLimiter.Release(); // GpuPrimeWorkLimiter.Release();
} }
} }
@@ -25,7 +25,7 @@ public class MersenneNumberResidueGpuTester(bool useGpuOrder)
// GPU residue variant: check 2^p % q == 1 for q = 2*p*k + 1. // GPU residue variant: check 2^p % q == 1 for q = 2*p*k + 1.
public void Scan(ulong exponent, UInt128 twoP, LastDigit lastDigit, UInt128 maxK, ref bool isPrime) public void Scan(ulong exponent, UInt128 twoP, LastDigit lastDigit, UInt128 maxK, ref bool isPrime)
{ {
GpuPrimeWorkLimiter.Acquire(); // GpuPrimeWorkLimiter.Acquire();
var accelerator = AcceleratorPool.Shared.Rent(); var accelerator = AcceleratorPool.Shared.Rent();
// Monitor.Enter(gpuLease.ExecutionLock); // Monitor.Enter(gpuLease.ExecutionLock);
@@ -110,7 +110,7 @@ public class MersenneNumberResidueGpuTester(bool useGpuOrder)
stream.Dispose(); stream.Dispose();
// Monitor.Exit(gpuLease.ExecutionLock); // Monitor.Exit(gpuLease.ExecutionLock);
gpuKernels.Dispose(); gpuKernels.Dispose();
GpuPrimeWorkLimiter.Release(); // GpuPrimeWorkLimiter.Release();
} }
private static Action<AcceleratorStream, Index1D, ulong, GpuUInt128, GpuUInt128, byte, ulong, ResidueAutomatonArgs, ArrayView<ulong>, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>> GetPow2ModKernel(Accelerator accelerator) private static Action<AcceleratorStream, Index1D, ulong, GpuUInt128, GpuUInt128, byte, ulong, ResidueAutomatonArgs, ArrayView<ulong>, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>> GetPow2ModKernel(Accelerator accelerator)
@@ -10,28 +10,29 @@ public static class Pow2MontgomeryGpuCalculator
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ulong CalculateKeep(ulong exponent, in MontgomeryDivisorData divisor) public static ulong CalculateKeep(ulong exponent, in MontgomeryDivisorData divisor)
{ {
GpuPrimeWorkLimiter.Acquire(); // GpuPrimeWorkLimiter.Acquire();
ulong result = 0UL;
var gpu = PrimeOrderCalculatorAccelerator.Rent(1); var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
Accelerator? accelerator = gpu.Accelerator; Accelerator? accelerator = gpu.Accelerator;
AcceleratorStream stream = AcceleratorStreamPool.Rent(accelerator);
MemoryBuffer1D<ulong, Stride1D.Dense> exponentBuffer = gpu.Input; MemoryBuffer1D<ulong, Stride1D.Dense> exponentBuffer = gpu.Input;
MemoryBuffer1D<ulong, Stride1D.Dense> resultBuffer = gpu.OutputUlong;
var kernel = gpu.KeepMontgomeryKernel;
AcceleratorStream stream = AcceleratorStreamPool.Rent(accelerator);
exponentBuffer.View.CopyFromCPU(stream, ref exponent, 1); exponentBuffer.View.CopyFromCPU(stream, ref exponent, 1);
// We don't need to worry about any left-overs here. // We don't need to worry about any left-overs here.
// resultBuffer.MemSetToZero(stream); // resultBuffer.MemSetToZero(stream);
MemoryBuffer1D<ulong, Stride1D.Dense> resultBuffer = gpu.OutputUlong;
var kernel = gpu.KeepMontgomeryKernel;
var kernelLauncher = kernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>>(); var kernelLauncher = kernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>>();
kernelLauncher(stream, 1, exponentBuffer.View, divisor, resultBuffer.View); kernelLauncher(stream, 1, exponentBuffer.View, divisor, resultBuffer.View);
ulong result = 0UL;
resultBuffer.View.CopyToCPU(stream, ref result, 1); resultBuffer.View.CopyToCPU(stream, ref result, 1);
stream.Synchronize(); stream.Synchronize();
AcceleratorStreamPool.Return(stream); AcceleratorStreamPool.Return(stream);
GpuPrimeWorkLimiter.Release(); // GpuPrimeWorkLimiter.Release();
PrimeOrderCalculatorAccelerator.Return(gpu); PrimeOrderCalculatorAccelerator.Return(gpu);
return result; return result;
@@ -40,50 +41,48 @@ public static class Pow2MontgomeryGpuCalculator
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ulong CalculateConvert(ulong exponent, in MontgomeryDivisorData divisor) public static ulong CalculateConvert(ulong exponent, in MontgomeryDivisorData divisor)
{ {
GpuPrimeWorkLimiter.Acquire(); // GpuPrimeWorkLimiter.Acquire();
ulong result = 0UL;
var gpu = PrimeOrderCalculatorAccelerator.Rent(1); var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
AcceleratorStream stream = AcceleratorStreamPool.Rent(gpu.Accelerator);
MemoryBuffer1D<ulong, Stride1D.Dense> exponentBuffer = gpu.Input; MemoryBuffer1D<ulong, Stride1D.Dense> exponentBuffer = gpu.Input;
MemoryBuffer1D<ulong, Stride1D.Dense> resultBuffer = gpu.OutputUlong;
AcceleratorStream stream = AcceleratorStreamPool.Rent(gpu.Accelerator);
exponentBuffer.View.CopyFromCPU(stream, ref exponent, 1); exponentBuffer.View.CopyFromCPU(stream, ref exponent, 1);
// We don't need to worry about any left-overs here. // We don't need to worry about any left-overs here.
// resultBuffer.MemSetToZero(stream); // resultBuffer.MemSetToZero(stream);
MemoryBuffer1D<ulong, Stride1D.Dense> resultBuffer = gpu.OutputUlong;
var kernel = gpu.ConvertToStandardKernel; var kernel = gpu.ConvertToStandardKernel;
kernel.Launch(stream, 1, 1, exponentBuffer.View, divisor, resultBuffer.View); kernel.Launch(stream, 1, 1, exponentBuffer.View, divisor, resultBuffer.View);
ulong result = 0UL;
resultBuffer.View.CopyToCPU(stream, ref result, 1); resultBuffer.View.CopyToCPU(stream, ref result, 1);
stream.Synchronize(); stream.Synchronize();
AcceleratorStreamPool.Return(stream);
GpuPrimeWorkLimiter.Release();
AcceleratorStreamPool.Return(stream);
// GpuPrimeWorkLimiter.Release();
PrimeOrderCalculatorAccelerator.Return(gpu); PrimeOrderCalculatorAccelerator.Return(gpu);
return result; return result;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ulong CalculateConvert(PrimeOrderCalculatorAccelerator gpu, ulong exponent, in MontgomeryDivisorData divisor) public static ulong CalculateConvert(PrimeOrderCalculatorAccelerator gpu, ulong exponent, in MontgomeryDivisorData divisor)
{ {
AcceleratorStream stream = AcceleratorStreamPool.Rent(gpu.Accelerator); ulong result = 0UL;
MemoryBuffer1D<ulong, Stride1D.Dense> exponentBuffer = gpu.Input; MemoryBuffer1D<ulong, Stride1D.Dense> exponentBuffer = gpu.Input;
MemoryBuffer1D<ulong, Stride1D.Dense> resultBuffer = gpu.OutputUlong;
var kernel = gpu.ConvertToStandardKernel;
AcceleratorStream stream = AcceleratorStreamPool.Rent(gpu.Accelerator);
exponentBuffer.View.CopyFromCPU(stream, ref exponent, 1); exponentBuffer.View.CopyFromCPU(stream, ref exponent, 1);
// We don't need to worry about any left-overs here. // We don't need to worry about any left-overs here.
// resultBuffer.MemSetToZero(stream); // resultBuffer.MemSetToZero(stream);
MemoryBuffer1D<ulong, Stride1D.Dense> resultBuffer = gpu.OutputUlong;
var kernel = gpu.ConvertToStandardKernel;
var kernelLauncher = kernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>>(); var kernelLauncher = kernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>>();
kernelLauncher(stream, 1,exponentBuffer.View, divisor, resultBuffer.View); kernelLauncher(stream, 1,exponentBuffer.View, divisor, resultBuffer.View);
ulong result = 0UL;
resultBuffer.View.CopyToCPU(stream, ref result, 1); resultBuffer.View.CopyToCPU(stream, ref result, 1);
stream.Synchronize(); stream.Synchronize();
AcceleratorStreamPool.Return(stream); AcceleratorStreamPool.Return(stream);
return result; return result;
@@ -225,7 +225,7 @@ internal static partial class PrimeOrderGpuHeuristics
try try
{ {
GpuPrimeWorkLimiter.Acquire(); // GpuPrimeWorkLimiter.Acquire();
Accelerator accelerator = AcceleratorPool.Shared.Rent(); Accelerator accelerator = AcceleratorPool.Shared.Rent();
AcceleratorStream stream = accelerator.CreateStream(); AcceleratorStream stream = accelerator.CreateStream();
@@ -290,7 +290,7 @@ internal static partial class PrimeOrderGpuHeuristics
countBuffer.Dispose(); countBuffer.Dispose();
remainingBuffer.Dispose(); remainingBuffer.Dispose();
fullyFactoredBuffer.Dispose(); fullyFactoredBuffer.Dispose();
GpuPrimeWorkLimiter.Release(); // GpuPrimeWorkLimiter.Release();
return true; return true;
} }
catch (CLException ex) catch (CLException ex)
@@ -402,7 +402,7 @@ internal static partial class PrimeOrderGpuHeuristics
{ {
order = 0UL; order = 0UL;
GpuPrimeWorkLimiter.Acquire(); // GpuPrimeWorkLimiter.Acquire();
Accelerator accelerator = AcceleratorPool.Shared.Rent(); Accelerator accelerator = AcceleratorPool.Shared.Rent();
AcceleratorStream stream = accelerator.CreateStream(); AcceleratorStream stream = accelerator.CreateStream();
@@ -494,7 +494,7 @@ internal static partial class PrimeOrderGpuHeuristics
stackProductBuffer.Dispose(); stackProductBuffer.Dispose();
resultBuffer.Dispose(); resultBuffer.Dispose();
statusBuffer.Dispose(); statusBuffer.Dispose();
GpuPrimeWorkLimiter.Release(); // GpuPrimeWorkLimiter.Release();
PrimeOrderKernelStatus kernelStatus = (PrimeOrderKernelStatus)status; PrimeOrderKernelStatus kernelStatus = (PrimeOrderKernelStatus)status;
if (kernelStatus == PrimeOrderKernelStatus.Fallback) if (kernelStatus == PrimeOrderKernelStatus.Fallback)
@@ -574,7 +574,7 @@ internal static partial class PrimeOrderGpuHeuristics
private static bool TryComputeOnGpu(ReadOnlySpan<ulong> exponents, ulong prime, in MontgomeryDivisorData divisorData, Span<ulong> results) private static bool TryComputeOnGpu(ReadOnlySpan<ulong> exponents, ulong prime, in MontgomeryDivisorData divisorData, Span<ulong> results)
{ {
GpuPrimeWorkLimiter.Acquire(); // GpuPrimeWorkLimiter.Acquire();
Accelerator accelerator = AcceleratorPool.Shared.Rent(); Accelerator accelerator = AcceleratorPool.Shared.Rent();
AcceleratorStream? stream = accelerator.CreateStream(); AcceleratorStream? stream = accelerator.CreateStream();
// TODO: These buffers should be allocated once per accelerator and only reallocated when the new length exceeds capacity. // TODO: These buffers should be allocated once per accelerator and only reallocated when the new length exceeds capacity.
@@ -604,7 +604,7 @@ internal static partial class PrimeOrderGpuHeuristics
stream = null; stream = null;
exponentBuffer.Dispose(); exponentBuffer.Dispose();
remainderBuffer.Dispose(); remainderBuffer.Dispose();
GpuPrimeWorkLimiter.Release(); // GpuPrimeWorkLimiter.Release();
} }
catch (Exception) catch (Exception)
{ {
@@ -612,7 +612,7 @@ internal static partial class PrimeOrderGpuHeuristics
stream?.Dispose(); stream?.Dispose();
exponentBuffer.Dispose(); exponentBuffer.Dispose();
remainderBuffer.Dispose(); remainderBuffer.Dispose();
GpuPrimeWorkLimiter.Release(); // GpuPrimeWorkLimiter.Release();
throw; throw;
} }
@@ -638,7 +638,7 @@ internal static partial class PrimeOrderGpuHeuristics
GpuUInt128[]? rentedExponents = null; GpuUInt128[]? rentedExponents = null;
GpuUInt128[]? rentedResults = null; GpuUInt128[]? rentedResults = null;
GpuPrimeWorkLimiter.Acquire(); // GpuPrimeWorkLimiter.Acquire();
ArrayPool<GpuUInt128> gpuUInt128Pool = ThreadStaticPools.GpuUInt128Pool; ArrayPool<GpuUInt128> gpuUInt128Pool = ThreadStaticPools.GpuUInt128Pool;
try try
@@ -704,7 +704,7 @@ internal static partial class PrimeOrderGpuHeuristics
gpuUInt128Pool.Return(rentedResults!, clearArray: false); gpuUInt128Pool.Return(rentedResults!, clearArray: false);
} }
GpuPrimeWorkLimiter.Release(); // GpuPrimeWorkLimiter.Release();
} }
} }
@@ -224,11 +224,11 @@ public sealed class HeuristicCombinedPrimeTester
private static bool HeuristicTrialDivisionGpuDetectsDivisor(ulong n, ulong maxDivisorSquare, byte nMod10) private static bool HeuristicTrialDivisionGpuDetectsDivisor(ulong n, ulong maxDivisorSquare, byte nMod10)
{ {
GpuPrimeWorkLimiter.Acquire(); // GpuPrimeWorkLimiter.Acquire();
var gpu = HeuristicPrimeTesterAccelerator.Rent(1); var gpu = HeuristicPrimeTesterAccelerator.Rent(1);
var accelerator = gpu.Accelerator; var accelerator = gpu.Accelerator;
var stream = gpu.Stream; var stream = gpu.Stream;
var kernel = HeuristicPrimeTesterAccelerator.GetHeuristicTrialDivisionKernel(accelerator); var kernel = HeuristicPrimeTesterAccelerator.HeuristicTrialDivisionKernel;
var flagView1D = gpu.HeuristicFlag.View; var flagView1D = gpu.HeuristicFlag.View;
var flagView = flagView1D.AsContiguous(); var flagView = flagView1D.AsContiguous();
@@ -251,7 +251,7 @@ public sealed class HeuristicCombinedPrimeTester
flagView1D.CopyToCPU(stream, ref compositeFlag, 1); flagView1D.CopyToCPU(stream, ref compositeFlag, 1);
stream.Synchronize(); stream.Synchronize();
GpuPrimeWorkLimiter.Release(); // GpuPrimeWorkLimiter.Release();
compositeDetected = compositeFlag != 0; compositeDetected = compositeFlag != 0;
HeuristicPrimeTesterAccelerator.Return(gpu); HeuristicPrimeTesterAccelerator.Return(gpu);
+2 -2
View File
@@ -241,7 +241,7 @@ public sealed class HeuristicPrimeTester
private bool HeuristicTrialDivisionGpuDetectsDivisor(ulong n, ulong maxDivisorSquare, byte nMod10) private bool HeuristicTrialDivisionGpuDetectsDivisor(ulong n, ulong maxDivisorSquare, byte nMod10)
{ {
GpuPrimeWorkLimiter.Acquire(); // GpuPrimeWorkLimiter.Acquire();
var gpu = HeuristicPrimeTesterAccelerator.Rent(1); var gpu = HeuristicPrimeTesterAccelerator.Rent(1);
var accelerator = gpu.Accelerator; var accelerator = gpu.Accelerator;
var stream = gpu.Stream; var stream = gpu.Stream;
@@ -307,7 +307,7 @@ public sealed class HeuristicPrimeTester
} }
gpu.Dispose(); gpu.Dispose();
GpuPrimeWorkLimiter.Release(); // GpuPrimeWorkLimiter.Release();
return compositeDetected; return compositeDetected;
} }
+2 -2
View File
@@ -804,7 +804,7 @@ public class MersenneDivisorCycles
divisors = pool.Rent(count); divisors = pool.Rent(count);
outCycles = pool.Rent(count); outCycles = pool.Rent(count);
GpuPrimeWorkLimiter.Acquire(); // GpuPrimeWorkLimiter.Acquire();
var accelerator = AcceleratorPool.Shared.Rent(); var accelerator = AcceleratorPool.Shared.Rent();
var stream = accelerator.CreateStream(); var stream = accelerator.CreateStream();
@@ -897,7 +897,7 @@ public class MersenneDivisorCycles
pool.Return(divisors, clearArray: false); pool.Return(divisors, clearArray: false);
pool.Return(outCycles, clearArray: false); pool.Return(outCycles, clearArray: false);
GpuPrimeWorkLimiter.Release(); // GpuPrimeWorkLimiter.Release();
} }
private static Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>> GetDivisorCycleKernel(Accelerator accelerator) private static Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>> GetDivisorCycleKernel(Accelerator accelerator)
+2 -5
View File
@@ -147,7 +147,7 @@ public sealed class MersenneNumberTester(
UInt128[] qs = qsBuffer; UInt128[] qs = qsBuffer;
GpuPrimeWorkLimiter.Acquire(); // GpuPrimeWorkLimiter.Acquire();
var accelerator = AcceleratorPool.Shared.Rent(); var accelerator = AcceleratorPool.Shared.Rent();
var stream = accelerator.CreateStream(); var stream = accelerator.CreateStream();
var orderKernel = GpuKernelPool.GetOrAddKernels(accelerator, stream, KernelType.OrderKernelScan).Order!; var orderKernel = GpuKernelPool.GetOrAddKernels(accelerator, stream, KernelType.OrderKernelScan).Order!;
@@ -164,11 +164,8 @@ public sealed class MersenneNumberTester(
while (offset < idx) while (offset < idx)
{ {
int count = Math.Min(batchSize, idx - offset); int count = Math.Min(batchSize, idx - offset);
// lock (accelerator)
{
qBuffer = accelerator.Allocate1D<GpuUInt128>(count); qBuffer = accelerator.Allocate1D<GpuUInt128>(count);
orderBuffer = accelerator.Allocate1D<ulong>(count); orderBuffer = accelerator.Allocate1D<ulong>(count);
}
// Convert to device-friendly GpuUInt128 on the fly // Convert to device-friendly GpuUInt128 on the fly
var tmp = gpuUInt128Pool.Rent(count); var tmp = gpuUInt128Pool.Rent(count);
@@ -204,7 +201,7 @@ public sealed class MersenneNumberTester(
} }
stream.Dispose(); stream.Dispose();
GpuPrimeWorkLimiter.Release(); // GpuPrimeWorkLimiter.Release();
uInt128Pool.Return(qs); uInt128Pool.Return(qs);
} }
+12 -17
View File
@@ -91,30 +91,30 @@ internal static partial class PrimeOrderCalculator
return phi; return phi;
} }
GpuPrimeWorkLimiter.Acquire(); // GpuPrimeWorkLimiter.Acquire();
ulong candidateOrder = InitializeStartingOrderCpu(gpu, prime, phi, divisorData); ulong candidateOrder = InitializeStartingOrderCpu(gpu, prime, phi, divisorData);
candidateOrder = ExponentLoweringCpu(candidateOrder, prime, phiFactors, divisorData); candidateOrder = ExponentLoweringCpu(candidateOrder, prime, phiFactors, divisorData);
if (TryConfirmOrderCpu(gpu, prime, candidateOrder, divisorData, config, out PartialFactorResult? orderFactors)) if (TryConfirmOrderCpu(gpu, prime, candidateOrder, divisorData, config, out PartialFactorResult? orderFactors))
{ {
GpuPrimeWorkLimiter.Release(); // GpuPrimeWorkLimiter.Release();
return candidateOrder; return candidateOrder;
} }
if (config.Mode == PrimeOrderMode.Strict) if (config.Mode == PrimeOrderMode.Strict)
{ {
orderFactors?.Dispose(); orderFactors?.Dispose();
GpuPrimeWorkLimiter.Release(); // GpuPrimeWorkLimiter.Release();
return CalculateByFactorizationGpu(gpu, prime, divisorData); return CalculateByFactorizationGpu(gpu, prime, divisorData);
} }
if (TryHeuristicFinishCpu(gpu, prime, candidateOrder, previousOrder, divisorData, config, phiFactors, orderFactors, out ulong order)) if (TryHeuristicFinishCpu(gpu, prime, candidateOrder, previousOrder, divisorData, config, phiFactors, orderFactors, out ulong order))
{ {
GpuPrimeWorkLimiter.Release(); // GpuPrimeWorkLimiter.Release();
return order; return order;
} }
GpuPrimeWorkLimiter.Release(); // GpuPrimeWorkLimiter.Release();
return candidateOrder; return candidateOrder;
} }
@@ -1148,7 +1148,7 @@ internal static partial class PrimeOrderCalculator
bool pollardRhoDeadlineReached = Stopwatch.GetTimestamp() > deadlineTimestamp; bool pollardRhoDeadlineReached = Stopwatch.GetTimestamp() > deadlineTimestamp;
if (!pollardRhoDeadlineReached) if (!pollardRhoDeadlineReached)
{ {
GpuPrimeWorkLimiter.Acquire(); // GpuPrimeWorkLimiter.Acquire();
while (compositeStack.Count > 0) while (compositeStack.Count > 0)
{ {
@@ -1200,7 +1200,7 @@ internal static partial class PrimeOrderCalculator
pollardRhoDeadlineReached = Stopwatch.GetTimestamp() > deadlineTimestamp; pollardRhoDeadlineReached = Stopwatch.GetTimestamp() > deadlineTimestamp;
} }
GpuPrimeWorkLimiter.Release(); // GpuPrimeWorkLimiter.Release();
} }
if (pollardRhoDeadlineReached) if (pollardRhoDeadlineReached)
@@ -1216,7 +1216,7 @@ internal static partial class PrimeOrderCalculator
bool cofactorContainsComposite = false; bool cofactorContainsComposite = false;
int pendingCount = pending.Count; int pendingCount = pending.Count;
int index = 0; int index = 0;
GpuPrimeWorkLimiter.Acquire(); // GpuPrimeWorkLimiter.Acquire();
for (; index < pendingCount; index++) for (; index < pendingCount; index++)
{ {
PendingEntry entry = pending[index]; PendingEntry entry = pending[index];
@@ -1280,7 +1280,7 @@ internal static partial class PrimeOrderCalculator
// cofactorIsPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(cofactor); // cofactorIsPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(cofactor);
} }
GpuPrimeWorkLimiter.Release(); // GpuPrimeWorkLimiter.Release();
// ArrayPool<FactorEntry> pool = ThreadStaticPools.FactorEntryPool; // ArrayPool<FactorEntry> pool = ThreadStaticPools.FactorEntryPool;
bool temp; bool temp;
@@ -1331,19 +1331,14 @@ internal static partial class PrimeOrderCalculator
// continue; // continue;
// } // }
// factorsArray[arrayIndex] = new FactorEntry(primeValue, exponentValue, true);
factorsArray[arrayIndex] = primeValue; factorsArray[arrayIndex] = primeValue;
exponentsArray[arrayIndex] = exponentValue; exponentsArray[arrayIndex] = exponentValue;
// cofactorIsPrimesArray[arrayIndex] = true;
arrayIndex++; arrayIndex++;
} }
// Span<FactorEntry> arraySpan = factorsArray.AsSpan(0, arrayIndex);
// Span<ulong> arraySpan = factorsArray.AsSpan(0, arrayIndex);
// arraySpan.Sort(static (a, b) => a.CompareTo(b));
Array.Sort(factorsArray, exponentsArray, 0, arrayIndex); Array.Sort(factorsArray, exponentsArray, 0, arrayIndex);
temp = cofactor == 1UL; temp = cofactor == 1UL;
// result = PartialFactorResult.Rent(factorsArray, exponentsArray, cofactorIsPrimesArray, cofactor, temp, arrayIndex, cofactorIsPrime);
result = PartialFactorResult.Rent(factorsArray, exponentsArray, cofactor, temp, arrayIndex, cofactorIsPrime); result = PartialFactorResult.Rent(factorsArray, exponentsArray, cofactor, temp, arrayIndex, cofactorIsPrime);
ReturnResult: ReturnResult:
@@ -1716,7 +1711,7 @@ internal static partial class PrimeOrderCalculator
ulong order = phi; ulong order = phi;
int entryCount = entries.Length; int entryCount = entries.Length;
GpuPrimeWorkLimiter.Acquire(); // GpuPrimeWorkLimiter.Acquire();
for (int i = 0; i < entryCount; i++) for (int i = 0; i < entryCount; i++)
{ {
ulong primeFactor = entries[i].Key; ulong primeFactor = entries[i].Key;
@@ -1744,7 +1739,7 @@ internal static partial class PrimeOrderCalculator
} }
} }
GpuPrimeWorkLimiter.Release(); // GpuPrimeWorkLimiter.Release();
return order; return order;
} }
@@ -39,7 +39,7 @@ internal static partial class PrimeOrderCalculator
var kernel = gpu.CheckFactorsKernel; var kernel = gpu.CheckFactorsKernel;
gpu.EnsureCapacity(entryCount, 1); gpu.EnsureCapacity(entryCount, 1);
GpuPrimeWorkLimiter.Acquire(); // GpuPrimeWorkLimiter.Acquire();
AcceleratorStream stream = AcceleratorStreamPool.Rent(gpu.Accelerator); AcceleratorStream stream = AcceleratorStreamPool.Rent(gpu.Accelerator);
gpu.Pow2ModEntriesToTestOnDevice.View.CopyFromCPU(stream, entries); gpu.Pow2ModEntriesToTestOnDevice.View.CopyFromCPU(stream, entries);
@@ -51,7 +51,7 @@ internal static partial class PrimeOrderCalculator
stream.Synchronize(); stream.Synchronize();
AcceleratorStreamPool.Return(stream); AcceleratorStreamPool.Return(stream);
GpuPrimeWorkLimiter.Release(); // GpuPrimeWorkLimiter.Release();
return order; return order;
} }
@@ -66,7 +66,7 @@ internal static partial class PrimeOrderCalculator
gpu.EnsureSmallPrimeFactorSlotsCapacity(GpuSmallPrimeFactorSlots); gpu.EnsureSmallPrimeFactorSlotsCapacity(GpuSmallPrimeFactorSlots);
var accelerator = gpu.Accelerator; var accelerator = gpu.Accelerator;
GpuPrimeWorkLimiter.Acquire(); // GpuPrimeWorkLimiter.Acquire();
var stream = AcceleratorStreamPool.Rent(accelerator); var stream = AcceleratorStreamPool.Rent(accelerator);
KernelContainer kernels = GpuKernelPool.GetOrAddKernels(accelerator, stream, KernelType.SmallPrimeFactorKernelScan); KernelContainer kernels = GpuKernelPool.GetOrAddKernels(accelerator, stream, KernelType.SmallPrimeFactorKernelScan);
SmallPrimeFactorViews tables = GpuKernelPool.GetSmallPrimeFactorTables(kernels); SmallPrimeFactorViews tables = GpuKernelPool.GetSmallPrimeFactorTables(kernels);
@@ -113,7 +113,7 @@ internal static partial class PrimeOrderCalculator
stream.Synchronize(); stream.Synchronize();
AcceleratorStreamPool.Return(stream); AcceleratorStreamPool.Return(stream);
GpuPrimeWorkLimiter.Release(); // GpuPrimeWorkLimiter.Release();
for (int i = 0; i < factorCount; i++) for (int i = 0; i < factorCount; i++)
{ {
@@ -136,7 +136,7 @@ internal static partial class PrimeOrderCalculator
gpu.EnsureSpecialMaxFactorsCapacity(factorCount); gpu.EnsureSpecialMaxFactorsCapacity(factorCount);
Accelerator accelerator = gpu.Accelerator; Accelerator accelerator = gpu.Accelerator;
GpuPrimeWorkLimiter.Acquire(); // GpuPrimeWorkLimiter.Acquire();
var stream = AcceleratorStreamPool.Rent(accelerator); var stream = AcceleratorStreamPool.Rent(accelerator);
var kernels = GpuKernelPool.GetOrAddKernels(accelerator, stream, KernelType.EvaluateSpecialMaxCandidatesKernel); var kernels = GpuKernelPool.GetOrAddKernels(accelerator, stream, KernelType.EvaluateSpecialMaxCandidatesKernel);
@@ -162,7 +162,7 @@ internal static partial class PrimeOrderCalculator
stream.Synchronize(); stream.Synchronize();
AcceleratorStreamPool.Return(stream); AcceleratorStreamPool.Return(stream);
GpuPrimeWorkLimiter.Release(); // GpuPrimeWorkLimiter.Release();
return result != 0; return result != 0;
} }
@@ -171,11 +171,12 @@ internal static partial class PrimeOrderCalculator
Span<ulong> randomStateSpan = stackalloc ulong[1]; Span<ulong> randomStateSpan = stackalloc ulong[1];
randomStateSpan[0] = ThreadStaticDeterministicRandomGpu.Exclusive.State; randomStateSpan[0] = ThreadStaticDeterministicRandomGpu.Exclusive.State;
Span<byte> factoredSpan = stackalloc byte[1];
Span<ulong> factorSpan = stackalloc ulong[1];
AcceleratorStream stream = AcceleratorStreamPool.Rent(gpu.Accelerator); AcceleratorStream stream = AcceleratorStreamPool.Rent(gpu.Accelerator);
gpu.Input.View.CopyFromCPU(stream, randomStateSpan); gpu.Input.View.CopyFromCPU(stream, randomStateSpan);
Span<byte> factoredSpan = stackalloc byte[1];
Span<ulong> factorSpan = stackalloc ulong[1];
var kernelLauncher = gpu.PollardRhoKernel.CreateLauncherDelegate<Action<AcceleratorStream, ulong, int, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<byte, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>>(); var kernelLauncher = gpu.PollardRhoKernel.CreateLauncherDelegate<Action<AcceleratorStream, ulong, int, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<byte, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>>();
kernelLauncher(stream, n, 1, gpu.Input.View, gpu.OutputByte.View, gpu.OutputUlong.View); kernelLauncher(stream, n, 1, gpu.Input.View, gpu.OutputByte.View, gpu.OutputUlong.View);
+18 -22
View File
@@ -1,7 +1,6 @@
using System.Buffers; using System.Buffers;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using ILGPU; using ILGPU;
using ILGPU.Runtime; using ILGPU.Runtime;
using PerfectNumbers.Core.Gpu; using PerfectNumbers.Core.Gpu;
@@ -93,15 +92,15 @@ public sealed class PrimeTester
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsPrimeGpu(ulong n) public static bool IsPrimeGpu(ulong n)
{ {
var gpu = PrimeOrderCalculatorAccelerator.Rent(1); byte flag = 0;
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
var inputView = gpu.PrimeTestInput.View; var inputView = gpu.PrimeTestInput.View;
var outputView = gpu.OutputByte.View; var outputView = gpu.OutputByte.View;
var kernel = gpu.SmallPrimeSieveKernel!; var kernel = gpu.SmallPrimeSieveKernel!;
GpuPrimeWorkLimiter.Acquire(); // GpuPrimeWorkLimiter.Acquire();
AcceleratorStream stream = AcceleratorStreamPool.Rent(gpu.Accelerator); AcceleratorStream stream = AcceleratorStreamPool.Rent(gpu.Accelerator);
// var stream = gpu.Stream!;
inputView.CopyFromCPU(stream, ref n, 1); inputView.CopyFromCPU(stream, ref n, 1);
var kernelLauncher = kernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>>>(); var kernelLauncher = kernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>>>();
@@ -120,13 +119,12 @@ public sealed class PrimeTester
gpu.DevicePrimesPow2LastNine.View, gpu.DevicePrimesPow2LastNine.View,
outputView); outputView);
byte flag = 0;
outputView.CopyToCPU(stream, ref flag, 1); outputView.CopyToCPU(stream, ref flag, 1);
stream.Synchronize(); stream.Synchronize();
AcceleratorStreamPool.Return(stream); AcceleratorStreamPool.Return(stream);
PrimeOrderCalculatorAccelerator.Return(gpu); PrimeOrderCalculatorAccelerator.Return(gpu);
GpuPrimeWorkLimiter.Release(); // GpuPrimeWorkLimiter.Release();
return flag != 0; return flag != 0;
} }
@@ -134,6 +132,7 @@ public sealed class PrimeTester
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsPrimeGpu(PrimeOrderCalculatorAccelerator gpu, ulong n) public static bool IsPrimeGpu(PrimeOrderCalculatorAccelerator gpu, ulong n)
{ {
byte flag = 0;
var input = gpu.PrimeTestInput; var input = gpu.PrimeTestInput;
var inputView = input.View; var inputView = input.View;
var output = gpu.OutputByte; var output = gpu.OutputByte;
@@ -159,7 +158,6 @@ public sealed class PrimeTester
gpu.DevicePrimesPow2LastNine.View, gpu.DevicePrimesPow2LastNine.View,
outputView); outputView);
byte flag = 0;
outputView.CopyToCPU(stream, ref flag, 1); outputView.CopyToCPU(stream, ref flag, 1);
stream.Synchronize(); stream.Synchronize();
AcceleratorStreamPool.Return(stream); AcceleratorStreamPool.Return(stream);
@@ -195,7 +193,7 @@ public sealed class PrimeTester
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void IsPrimeBatchGpu(ReadOnlySpan<ulong> values, Span<byte> results) public static void IsPrimeBatchGpu(ReadOnlySpan<ulong> values, Span<byte> results)
{ {
GpuPrimeWorkLimiter.Acquire(); // GpuPrimeWorkLimiter.Acquire();
var gpu = PrimeOrderCalculatorAccelerator.Rent(GpuBatchSize); var gpu = PrimeOrderCalculatorAccelerator.Rent(GpuBatchSize);
var accelerator = gpu.Accelerator; var accelerator = gpu.Accelerator;
var kernel = gpu.SmallPrimeSieveKernel!; var kernel = gpu.SmallPrimeSieveKernel!;
@@ -240,7 +238,7 @@ public sealed class PrimeTester
stream.Synchronize(); stream.Synchronize();
AcceleratorStreamPool.Return(stream); AcceleratorStreamPool.Return(stream);
PrimeOrderCalculatorAccelerator.Return(gpu); PrimeOrderCalculatorAccelerator.Return(gpu);
GpuPrimeWorkLimiter.Release(); // GpuPrimeWorkLimiter.Release();
} }
// Expose cache clearing for accelerator disposal coordination // Expose cache clearing for accelerator disposal coordination
@@ -276,31 +274,27 @@ public sealed class PrimeTester
// TODO: Route this batch helper through the shared GPU kernel pool from // TODO: Route this batch helper through the shared GPU kernel pool from
// GpuUInt128BinaryGcdBenchmarks so we reuse cached kernels, pinned host buffers, // GpuUInt128BinaryGcdBenchmarks so we reuse cached kernels, pinned host buffers,
// and divisor-cycle staging instead of allocating new device buffers per call. // and divisor-cycle staging instead of allocating new device buffers per call.
var gpu = PrimeOrderCalculatorAccelerator.Rent(1); // Check in benchmarks, which implementation was the fastest, is compatible with GPU,
var accelerator = gpu.Accelerator; // and implement it.
int length = values.Length; int length = values.Length;
ArrayPool<ulong> pool = ThreadStaticPools.UlongPool; ArrayPool<ulong> pool = ThreadStaticPools.UlongPool;
ulong[] temp = pool.Rent(length);
values.CopyTo(temp);
MemoryBuffer1D<ulong, Stride1D.Dense>? inputBuffer; var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
MemoryBuffer1D<byte, Stride1D.Dense>? resultBuffer; var accelerator = gpu.Accelerator;
gpu.EnsureCapacity(0, length);
inputBuffer = accelerator.Allocate1D<ulong>(length); MemoryBuffer1D<ulong, Stride1D.Dense>? inputBuffer = gpu.PrimeTestInput;
resultBuffer = accelerator.Allocate1D<byte>(length); MemoryBuffer1D<byte, Stride1D.Dense>? resultBuffer = gpu.OutputByte;
AcceleratorStream stream = AcceleratorStreamPool.Rent(accelerator); AcceleratorStream stream = AcceleratorStreamPool.Rent(accelerator);
inputBuffer.View.CopyFromCPU(stream, ref temp[0], length); inputBuffer.View.CopyFromCPU(stream, values);
var kernel = GetSharesFactorKernel(accelerator); var kernel = GetSharesFactorKernel(accelerator);
kernel(stream, length, inputBuffer.View, resultBuffer.View); kernel(stream, length, inputBuffer.View, resultBuffer.View);
resultBuffer.View.CopyToCPU(stream, in results); resultBuffer.View.CopyToCPU(stream, in results);
stream.Synchronize(); stream.Synchronize();
AcceleratorStreamPool.Return(stream); AcceleratorStreamPool.Return(stream);
pool.Return(temp, clearArray: false);
resultBuffer.Dispose();
inputBuffer.Dispose();
PrimeOrderCalculatorAccelerator.Return(gpu); PrimeOrderCalculatorAccelerator.Return(gpu);
} }
@@ -323,6 +317,8 @@ public sealed class PrimeTester
// TODO: Swap this handwritten binary GCD for the optimized helper measured in // TODO: Swap this handwritten binary GCD for the optimized helper measured in
// GpuUInt128BinaryGcdBenchmarks so CPU callers share the faster subtract-less // GpuUInt128BinaryGcdBenchmarks so CPU callers share the faster subtract-less
// ladder once the common implementation is promoted into PerfectNumbers.Core. // ladder once the common implementation is promoted into PerfectNumbers.Core.
// You have an example in the benchmarks and you already implemented it in
// GpuUInt128, iirc.
if (u == 0UL) if (u == 0UL)
{ {
return v; return v;