Merge pull request #3 from mlemanczyk/codex/update-evenperfectbitscanner-gpu-disposal
Avoid using declarations for GPU resources to not rely on GC to release them, which could cause delays.
This commit is contained in:
9 files changed
+273
-212
No files matched your search
@@ -542,9 +542,12 @@ 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)
|
||||||
{
|
{
|
||||||
using var lease = GetKernel(useGpuOrder: true);
|
var lease = GetKernel(useGpuOrder: true);
|
||||||
var accelerator = lease.Accelerator;
|
var accelerator = lease.Accelerator;
|
||||||
using var stream = accelerator.CreateStream();
|
var stream = accelerator.CreateStream();
|
||||||
action(accelerator, stream);
|
action(accelerator, stream);
|
||||||
|
stream.Dispose();
|
||||||
|
lease.Dispose();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9,69 +9,73 @@ public class MersenneNumberIncrementalGpuTester(GpuKernelType kernelType, bool u
|
|||||||
private readonly GpuKernelType _kernelType = kernelType;
|
private readonly GpuKernelType _kernelType = kernelType;
|
||||||
private readonly bool _useGpuOrder = useGpuOrder;
|
private readonly bool _useGpuOrder = useGpuOrder;
|
||||||
|
|
||||||
public void Scan(ulong exponent, UInt128 twoP, bool lastIsSeven, UInt128 maxK, ref bool isPrime)
|
public void Scan(ulong exponent, UInt128 twoP, bool lastIsSeven, UInt128 maxK, ref bool isPrime)
|
||||||
{
|
{
|
||||||
using var gpuLease = GpuKernelPool.GetKernel(_useGpuOrder);
|
var gpuLease = GpuKernelPool.GetKernel(_useGpuOrder);
|
||||||
var accelerator = gpuLease.Accelerator;
|
var accelerator = gpuLease.Accelerator;
|
||||||
int batchSize = GpuConstants.ScanBatchSize; // large batch improves GPU occupancy
|
int batchSize = GpuConstants.ScanBatchSize; // large batch improves GPU occupancy
|
||||||
UInt128 kStart = 1UL;
|
UInt128 kStart = 1UL;
|
||||||
ulong divMul = (ulong)((((UInt128)1 << 64) - UInt128.One) / exponent) + 1UL;
|
ulong divMul = (ulong)((((UInt128)1 << 64) - UInt128.One) / exponent) + 1UL;
|
||||||
byte last = lastIsSeven ? (byte)1 : (byte)0; // ILGPU kernels do not support bool parameters
|
byte last = lastIsSeven ? (byte)1 : (byte)0; // ILGPU kernels do not support bool parameters
|
||||||
|
|
||||||
var kernel = (_kernelType == GpuKernelType.Pow2Mod)
|
var kernel = (_kernelType == GpuKernelType.Pow2Mod)
|
||||||
? gpuLease.Pow2ModKernel
|
? gpuLease.Pow2ModKernel
|
||||||
: gpuLease.IncrementalKernel;
|
: gpuLease.IncrementalKernel;
|
||||||
|
|
||||||
using var orderBuffer = accelerator.Allocate1D<ulong>(batchSize);
|
var orderBuffer = accelerator.Allocate1D<ulong>(batchSize);
|
||||||
// Avoid giant stack allocations that can trigger StackOverflow when batchSize is large.
|
// Avoid giant stack allocations that can trigger StackOverflow when batchSize is large.
|
||||||
// Rent a reusable array from the shared pool instead.
|
// Rent a reusable array from the shared pool instead.
|
||||||
ulong[] orderArray = ArrayPool<ulong>.Shared.Rent(batchSize);
|
ulong[] orderArray = ArrayPool<ulong>.Shared.Rent(batchSize);
|
||||||
UInt128 remaining;
|
UInt128 remaining;
|
||||||
int currentSize;
|
int currentSize;
|
||||||
int i;
|
int i;
|
||||||
UInt128 q = UInt128.Zero;
|
UInt128 q = UInt128.Zero;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
while (kStart <= maxK && Volatile.Read(ref isPrime))
|
while (kStart <= maxK && Volatile.Read(ref isPrime))
|
||||||
{
|
{
|
||||||
remaining = maxK - kStart + UInt128.One;
|
remaining = maxK - kStart + UInt128.One;
|
||||||
currentSize = remaining > (UInt128)batchSize ? batchSize : (int)remaining;
|
currentSize = remaining > (UInt128)batchSize ? batchSize : (int)remaining;
|
||||||
Span<ulong> orders = orderArray.AsSpan(0, currentSize);
|
Span<ulong> orders = orderArray.AsSpan(0, currentSize);
|
||||||
// Precompute residue automaton bases for this batch
|
// Precompute residue automaton bases for this batch
|
||||||
UInt128 q0 = twoP * kStart + UInt128.One;
|
UInt128 q0 = twoP * kStart + UInt128.One;
|
||||||
ulong q0m10 = q0.Mod10();
|
ulong q0m10 = q0.Mod10();
|
||||||
ulong q0m8 = q0.Mod8();
|
ulong q0m8 = q0.Mod8();
|
||||||
ulong q0m3 = q0.Mod3();
|
ulong q0m3 = q0.Mod3();
|
||||||
ulong q0m5 = q0.Mod5();
|
ulong q0m5 = q0.Mod5();
|
||||||
ulong step10 = ((exponent % 10UL) << 1) % 10UL;
|
ulong step10 = ((exponent % 10UL) << 1) % 10UL;
|
||||||
ulong step8 = ((exponent & 7UL) << 1) & 7UL;
|
ulong step8 = ((exponent & 7UL) << 1) & 7UL;
|
||||||
ulong step3 = ((exponent % 3UL) << 1) % 3UL;
|
ulong step3 = ((exponent % 3UL) << 1) % 3UL;
|
||||||
ulong step5 = ((exponent % 5UL) << 1) % 5UL;
|
ulong step5 = ((exponent % 5UL) << 1) % 5UL;
|
||||||
|
|
||||||
var smallCyclesView = GpuKernelPool.EnsureSmallCyclesOnDevice(accelerator);
|
var smallCyclesView = GpuKernelPool.EnsureSmallCyclesOnDevice(accelerator);
|
||||||
kernel(currentSize, exponent, (GpuUInt128)twoP, (GpuUInt128)kStart, last, divMul,
|
kernel(currentSize, exponent, (GpuUInt128)twoP, (GpuUInt128)kStart, last, divMul,
|
||||||
q0m10, q0m8, q0m3, q0m5, orderBuffer.View, smallCyclesView);
|
q0m10, q0m8, q0m3, q0m5, orderBuffer.View, smallCyclesView);
|
||||||
|
|
||||||
accelerator.Synchronize();
|
accelerator.Synchronize();
|
||||||
orderBuffer.View.CopyToCPU(ref MemoryMarshal.GetReference(orders), currentSize);
|
orderBuffer.View.CopyToCPU(ref MemoryMarshal.GetReference(orders), currentSize);
|
||||||
q = twoP * kStart + UInt128.One;
|
q = twoP * kStart + UInt128.One;
|
||||||
for (i = 0; i < currentSize && Volatile.Read(ref isPrime); i++, q += twoP)
|
for (i = 0; i < currentSize && Volatile.Read(ref isPrime); i++, q += twoP)
|
||||||
{
|
{
|
||||||
if (orders[i] != 0UL)
|
if (orders[i] != 0UL)
|
||||||
{
|
{
|
||||||
if (q.IsPrimeCandidate())
|
if (q.IsPrimeCandidate())
|
||||||
{
|
{
|
||||||
Volatile.Write(ref isPrime, false);
|
Volatile.Write(ref isPrime, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
kStart += (UInt128)currentSize;
|
kStart += (UInt128)currentSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
ArrayPool<ulong>.Shared.Return(orderArray);
|
ArrayPool<ulong>.Shared.Return(orderArray);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
orderBuffer.Dispose();
|
||||||
|
gpuLease.Dispose();
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -55,30 +55,39 @@ public class MersenneNumberLucasLehmerGpuTester
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
using var limiter = GpuPrimeWorkLimiter.Acquire();
|
var limiter = GpuPrimeWorkLimiter.Acquire();
|
||||||
|
bool result;
|
||||||
if (exponent >= 128UL)
|
if (exponent >= 128UL)
|
||||||
{
|
{
|
||||||
if (!TryGetNttParameters(exponent, out var nttMod, out var primitiveRoot))
|
if (!TryGetNttParameters(exponent, out var nttMod, out var primitiveRoot))
|
||||||
{
|
{
|
||||||
|
limiter.Dispose();
|
||||||
throw new NotSupportedException("NTT parameters for the given exponent are not available.");
|
throw new NotSupportedException("NTT parameters for the given exponent are not available.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return IsMersennePrimeNtt(exponent, nttMod, primitiveRoot, runOnGpu);
|
result = IsMersennePrimeNtt(exponent, nttMod, primitiveRoot, runOnGpu);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var gpu = GpuContextPool.RentPreferred(preferCpu: !runOnGpu);
|
||||||
|
var accelerator = gpu.Accelerator;
|
||||||
|
var kernel = GetKernel(accelerator);
|
||||||
|
var modulus = new GpuUInt128(((UInt128)1 << (int)exponent) - 1UL);
|
||||||
|
var buffer = accelerator.Allocate1D<GpuUInt128>(1);
|
||||||
|
kernel(1, exponent, modulus, buffer.View);
|
||||||
|
accelerator.Synchronize();
|
||||||
|
result = buffer.GetAsArray1D()[0].IsZero;
|
||||||
|
buffer.Dispose();
|
||||||
|
gpu.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
using var gpu = GpuContextPool.RentPreferred(preferCpu: !runOnGpu);
|
limiter.Dispose();
|
||||||
var accelerator = gpu.Accelerator;
|
return result;
|
||||||
var kernel = GetKernel(accelerator);
|
|
||||||
var modulus = new GpuUInt128(((UInt128)1 << (int)exponent) - 1UL);
|
|
||||||
using var buffer = accelerator.Allocate1D<GpuUInt128>(1);
|
|
||||||
kernel(1, exponent, modulus, buffer.View);
|
|
||||||
accelerator.Synchronize();
|
|
||||||
return buffer.GetAsArray1D()[0].IsZero;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsMersennePrimeNtt(ulong exponent, GpuUInt128 nttMod, GpuUInt128 primitiveRoot, bool runOnGpu)
|
private bool IsMersennePrimeNtt(ulong exponent, GpuUInt128 nttMod, GpuUInt128 primitiveRoot, bool runOnGpu)
|
||||||
{
|
{
|
||||||
using var gpu = GpuContextPool.RentPreferred(preferCpu: !runOnGpu);
|
var gpu = GpuContextPool.RentPreferred(preferCpu: !runOnGpu);
|
||||||
var accelerator = gpu.Accelerator;
|
var accelerator = gpu.Accelerator;
|
||||||
var addKernel = GetAddSmallKernel(accelerator);
|
var addKernel = GetAddSmallKernel(accelerator);
|
||||||
var subKernel = GetSubSmallKernel(accelerator);
|
var subKernel = GetSubSmallKernel(accelerator);
|
||||||
@@ -92,7 +101,7 @@ public class MersenneNumberLucasLehmerGpuTester
|
|||||||
{
|
{
|
||||||
transformLength <<= 1;
|
transformLength <<= 1;
|
||||||
}
|
}
|
||||||
using var stateBuffer = accelerator.Allocate1D<GpuUInt128>(transformLength);
|
var stateBuffer = accelerator.Allocate1D<GpuUInt128>(transformLength);
|
||||||
stateBuffer.MemSetToZero();
|
stateBuffer.MemSetToZero();
|
||||||
addKernel(1, 4UL, stateBuffer.View);
|
addKernel(1, 4UL, stateBuffer.View);
|
||||||
|
|
||||||
@@ -121,12 +130,16 @@ public class MersenneNumberLucasLehmerGpuTester
|
|||||||
|
|
||||||
reduceKernel(1, exponent, stateBuffer.View);
|
reduceKernel(1, exponent, stateBuffer.View);
|
||||||
|
|
||||||
using var resultBuffer = accelerator.Allocate1D<byte>(1);
|
var resultBuffer = accelerator.Allocate1D<byte>(1);
|
||||||
zeroKernel(1, stateBuffer.View, resultBuffer.View);
|
zeroKernel(1, stateBuffer.View, resultBuffer.View);
|
||||||
accelerator.Synchronize();
|
accelerator.Synchronize();
|
||||||
byte[] result = new byte[1];
|
byte[] result = new byte[1];
|
||||||
resultBuffer.View.CopyToCPU(result);
|
resultBuffer.View.CopyToCPU(result);
|
||||||
return result[0] != 0;
|
bool isPrime = result[0] != 0;
|
||||||
|
resultBuffer.Dispose();
|
||||||
|
stateBuffer.Dispose();
|
||||||
|
gpu.Dispose();
|
||||||
|
return isPrime;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly ConcurrentDictionary<int, (GpuUInt128 Modulus, GpuUInt128 PrimitiveRoot)> NttParameterCache = new()
|
private static readonly ConcurrentDictionary<int, (GpuUInt128 Modulus, GpuUInt128 PrimitiveRoot)> NttParameterCache = new()
|
||||||
|
|||||||
@@ -7,14 +7,14 @@ public class MersenneNumberOrderGpuTester(GpuKernelType kernelType, bool useGpuO
|
|||||||
private readonly GpuKernelType _kernelType = kernelType;
|
private readonly GpuKernelType _kernelType = kernelType;
|
||||||
private readonly bool _useGpuOrder = useGpuOrder;
|
private readonly bool _useGpuOrder = useGpuOrder;
|
||||||
|
|
||||||
public void Scan(ulong exponent, UInt128 twoP, bool lastIsSeven, UInt128 maxK, ref bool isPrime)
|
public void Scan(ulong exponent, UInt128 twoP, bool lastIsSeven, UInt128 maxK, ref bool isPrime)
|
||||||
{
|
{
|
||||||
using var gpuLease = GpuKernelPool.GetKernel(_useGpuOrder);
|
var gpuLease = GpuKernelPool.GetKernel(_useGpuOrder);
|
||||||
var accelerator = gpuLease.Accelerator;
|
var accelerator = gpuLease.Accelerator;
|
||||||
int batchSize = GpuConstants.ScanBatchSize; // large batch improves GPU occupancy and avoids TDR
|
int batchSize = GpuConstants.ScanBatchSize; // large batch improves GPU occupancy and avoids TDR
|
||||||
UInt128 kStart = UInt128.One;
|
UInt128 kStart = UInt128.One;
|
||||||
ulong divMul = (ulong)((((UInt128)1 << 64) - UInt128.One) / exponent) + 1UL;
|
ulong divMul = (ulong)((((UInt128)1 << 64) - UInt128.One) / exponent) + 1UL;
|
||||||
byte last = lastIsSeven ? (byte)1 : (byte)0; // ILGPU kernels do not support bool parameters
|
byte last = lastIsSeven ? (byte)1 : (byte)0; // ILGPU kernels do not support bool parameters
|
||||||
|
|
||||||
var kernel = _kernelType switch
|
var kernel = _kernelType switch
|
||||||
{
|
{
|
||||||
@@ -22,42 +22,46 @@ public class MersenneNumberOrderGpuTester(GpuKernelType kernelType, bool useGpuO
|
|||||||
_ => gpuLease.IncrementalOrderKernel,
|
_ => gpuLease.IncrementalOrderKernel,
|
||||||
};
|
};
|
||||||
|
|
||||||
using var foundBuffer = accelerator.Allocate1D<int>(1);
|
var foundBuffer = accelerator.Allocate1D<int>(1);
|
||||||
UInt128 remaining;
|
UInt128 remaining;
|
||||||
int currentSize;
|
int currentSize;
|
||||||
int found = 0;
|
int found = 0;
|
||||||
while (kStart <= maxK && Volatile.Read(ref isPrime))
|
while (kStart <= maxK && Volatile.Read(ref isPrime))
|
||||||
{
|
{
|
||||||
remaining = maxK - kStart + 1UL;
|
remaining = maxK - kStart + 1UL;
|
||||||
currentSize = remaining > (UInt128)batchSize ? batchSize : (int)remaining;
|
currentSize = remaining > (UInt128)batchSize ? batchSize : (int)remaining;
|
||||||
foundBuffer.MemSetToZero();
|
foundBuffer.MemSetToZero();
|
||||||
// Precompute residue automaton bases for this batch
|
// Precompute residue automaton bases for this batch
|
||||||
UInt128 q0 = twoP * kStart + 1UL;
|
UInt128 q0 = twoP * kStart + 1UL;
|
||||||
ulong q0m10 = q0.Mod10();
|
ulong q0m10 = q0.Mod10();
|
||||||
ulong q0m8 = q0.Mod8();
|
ulong q0m8 = q0.Mod8();
|
||||||
ulong q0m3 = q0.Mod3();
|
ulong q0m3 = q0.Mod3();
|
||||||
ulong q0m5 = q0.Mod5();
|
ulong q0m5 = q0.Mod5();
|
||||||
ulong step10 = ((exponent % 10UL) << 1) % 10UL;
|
ulong step10 = ((exponent % 10UL) << 1) % 10UL;
|
||||||
ulong step8 = ((exponent & 7UL) << 1) & 7UL;
|
ulong step8 = ((exponent & 7UL) << 1) & 7UL;
|
||||||
ulong step3 = ((exponent % 3UL) << 1) % 3UL;
|
ulong step3 = ((exponent % 3UL) << 1) % 3UL;
|
||||||
ulong step5 = ((exponent % 5UL) << 1) % 5UL;
|
ulong step5 = ((exponent % 5UL) << 1) % 5UL;
|
||||||
var ra = new ResidueAutomatonArgs(q0m10, step10, q0m8, step8, q0m3, step3, q0m5, step5);
|
var ra = new ResidueAutomatonArgs(q0m10, step10, q0m8, step8, q0m3, step3, q0m5, step5);
|
||||||
|
|
||||||
|
|
||||||
// Ensure device has small cycles table for early rejections in order kernels
|
// Ensure device has small cycles table for early rejections in order kernels
|
||||||
var smallCyclesView = GpuKernelPool.EnsureSmallCyclesOnDevice(accelerator);
|
var smallCyclesView = GpuKernelPool.EnsureSmallCyclesOnDevice(accelerator);
|
||||||
kernel(currentSize, exponent, (GpuUInt128)twoP, (GpuUInt128)kStart, last, divMul,
|
kernel(currentSize, exponent, (GpuUInt128)twoP, (GpuUInt128)kStart, last, divMul,
|
||||||
ra, foundBuffer.View, smallCyclesView);
|
ra, foundBuffer.View, smallCyclesView);
|
||||||
|
|
||||||
accelerator.Synchronize();
|
accelerator.Synchronize();
|
||||||
foundBuffer.View.CopyToCPU(ref found, 1);
|
foundBuffer.View.CopyToCPU(ref found, 1);
|
||||||
if (found != 0)
|
if (found != 0)
|
||||||
{
|
{
|
||||||
Volatile.Write(ref isPrime, false);
|
Volatile.Write(ref isPrime, false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
kStart += (UInt128)currentSize;
|
kStart += (UInt128)currentSize;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
foundBuffer.Dispose();
|
||||||
|
gpuLease.Dispose();
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -14,54 +14,54 @@ 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, bool lastIsSeven, UInt128 maxK, ref bool isPrime)
|
public void Scan(ulong exponent, UInt128 twoP, bool lastIsSeven, UInt128 maxK, ref bool isPrime)
|
||||||
{
|
{
|
||||||
using var gpuLease = GpuKernelPool.GetKernel(_useGpuOrder);
|
var gpuLease = GpuKernelPool.GetKernel(_useGpuOrder);
|
||||||
var accelerator = gpuLease.Accelerator;
|
var accelerator = gpuLease.Accelerator;
|
||||||
// Ensure device has small cycles table for in-kernel lookup
|
// Ensure device has small cycles table for in-kernel lookup
|
||||||
var smallCyclesView = GpuKernelPool.EnsureSmallCyclesOnDevice(accelerator);
|
var smallCyclesView = GpuKernelPool.EnsureSmallCyclesOnDevice(accelerator);
|
||||||
int batchSize = GpuConstants.ScanBatchSize;
|
int batchSize = GpuConstants.ScanBatchSize;
|
||||||
UInt128 kStart = 1UL;
|
UInt128 kStart = 1UL;
|
||||||
byte last = lastIsSeven ? (byte)1 : (byte)0;
|
byte last = lastIsSeven ? (byte)1 : (byte)0;
|
||||||
var kernel = gpuLease.Pow2ModKernel;
|
var kernel = gpuLease.Pow2ModKernel;
|
||||||
|
|
||||||
using var orderBuffer = accelerator.Allocate1D<ulong>(batchSize);
|
var orderBuffer = accelerator.Allocate1D<ulong>(batchSize);
|
||||||
ulong[] orderArray = ArrayPool<ulong>.Shared.Rent(batchSize);
|
ulong[] orderArray = ArrayPool<ulong>.Shared.Rent(batchSize);
|
||||||
UInt128 remaining;
|
UInt128 remaining;
|
||||||
int currentSize;
|
int currentSize;
|
||||||
int i;
|
int i;
|
||||||
UInt128 batchSize128 = (UInt128)batchSize,
|
UInt128 batchSize128 = (UInt128)batchSize,
|
||||||
q = UInt128.Zero;
|
q = UInt128.Zero;
|
||||||
Span<ulong> orders = orderArray.AsSpan(0, batchSize);
|
Span<ulong> orders = orderArray.AsSpan(0, batchSize);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
while (kStart < maxK && Volatile.Read(ref isPrime))
|
while (kStart < maxK && Volatile.Read(ref isPrime))
|
||||||
{
|
{
|
||||||
remaining = maxK - kStart;
|
remaining = maxK - kStart;
|
||||||
if (remaining > batchSize128)
|
if (remaining > batchSize128)
|
||||||
{
|
{
|
||||||
currentSize = batchSize;
|
currentSize = batchSize;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
currentSize = (int)remaining;
|
currentSize = (int)remaining;
|
||||||
orders = orderArray.AsSpan(0, currentSize);
|
orders = orderArray.AsSpan(0, currentSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
q = twoP * kStart + UInt128.One;
|
q = twoP * kStart + UInt128.One;
|
||||||
q.Mod10_8_5_3(out ulong q0m10, out ulong q0m8, out ulong q0m5, out ulong q0m3);
|
q.Mod10_8_5_3(out ulong q0m10, out ulong q0m8, out ulong q0m5, out ulong q0m3);
|
||||||
ulong step10 = ((exponent % 10UL) << 1) % 10UL;
|
ulong step10 = ((exponent % 10UL) << 1) % 10UL;
|
||||||
ulong step8 = ((exponent & 7UL) << 1) & 7UL;
|
ulong step8 = ((exponent & 7UL) << 1) & 7UL;
|
||||||
ulong step3 = ((exponent % 3UL) << 1) % 3UL;
|
ulong step3 = ((exponent % 3UL) << 1) % 3UL;
|
||||||
ulong step5 = ((exponent % 5UL) << 1) % 5UL;
|
ulong step5 = ((exponent % 5UL) << 1) % 5UL;
|
||||||
|
|
||||||
kernel(currentSize, exponent, (GpuUInt128)twoP, (GpuUInt128)kStart, last, 0UL,
|
kernel(currentSize, exponent, (GpuUInt128)twoP, (GpuUInt128)kStart, last, 0UL,
|
||||||
q0m10, q0m8, q0m3, q0m5, orderBuffer.View, smallCyclesView);
|
q0m10, q0m8, q0m3, q0m5, orderBuffer.View, smallCyclesView);
|
||||||
|
|
||||||
accelerator.Synchronize();
|
accelerator.Synchronize();
|
||||||
orderBuffer.View.CopyToCPU(ref MemoryMarshal.GetReference(orders), currentSize);
|
orderBuffer.View.CopyToCPU(ref MemoryMarshal.GetReference(orders), currentSize);
|
||||||
if (!Volatile.Read(ref isPrime))
|
if (!Volatile.Read(ref isPrime))
|
||||||
{
|
{
|
||||||
return;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < currentSize; i++, q += twoP)
|
for (i = 0; i < currentSize; i++, q += twoP)
|
||||||
{
|
{
|
||||||
@@ -72,12 +72,16 @@ public class MersenneNumberResidueGpuTester(bool useGpuOrder)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
kStart += batchSize128;
|
kStart += batchSize128;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
ArrayPool<ulong>.Shared.Return(orderArray);
|
ArrayPool<ulong>.Shared.Return(orderArray);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
orderBuffer.Dispose();
|
||||||
|
gpuLease.Dispose();
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -804,19 +804,22 @@ public static class NttGpuMath
|
|||||||
{
|
{
|
||||||
int n = values.Length;
|
int n = values.Length;
|
||||||
int bits = (int)Math.Log2(n);
|
int bits = (int)Math.Log2(n);
|
||||||
using var gpu = GpuContextPool.Rent();
|
var gpu = GpuContextPool.Rent();
|
||||||
var accelerator = gpu.Accelerator;
|
var accelerator = gpu.Accelerator;
|
||||||
var kernel = GetBitReverseKernel(accelerator);
|
var kernel = GetBitReverseKernel(accelerator);
|
||||||
var pool = ArrayPool<GpuUInt128>.Shared;
|
var pool = ArrayPool<GpuUInt128>.Shared;
|
||||||
var array = pool.Rent(n);
|
var array = pool.Rent(n);
|
||||||
values.CopyTo(array);
|
values.CopyTo(array);
|
||||||
using var buffer = accelerator.Allocate1D<GpuUInt128>(n);
|
var buffer = accelerator.Allocate1D<GpuUInt128>(n);
|
||||||
buffer.View.CopyFromCPU(ref array[0], n);
|
buffer.View.CopyFromCPU(ref array[0], n);
|
||||||
kernel(n, buffer.View, bits);
|
kernel(n, buffer.View, bits);
|
||||||
accelerator.Synchronize();
|
accelerator.Synchronize();
|
||||||
buffer.View.CopyToCPU(ref array[0], n);
|
buffer.View.CopyToCPU(ref array[0], n);
|
||||||
array.AsSpan(0, n).CopyTo(values);
|
array.AsSpan(0, n).CopyTo(values);
|
||||||
pool.Return(array, clearArray: true);
|
pool.Return(array, clearArray: true);
|
||||||
|
buffer.Dispose();
|
||||||
|
gpu.Dispose();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Forward(Span<GpuUInt128> values, GpuUInt128 modulus, GpuUInt128 primitiveRoot)
|
public static void Forward(Span<GpuUInt128> values, GpuUInt128 modulus, GpuUInt128 primitiveRoot)
|
||||||
@@ -863,15 +866,15 @@ public static class NttGpuMath
|
|||||||
private static void ForwardGpuReference(Span<GpuUInt128> values, GpuUInt128 modulus, GpuUInt128 primitiveRoot)
|
private static void ForwardGpuReference(Span<GpuUInt128> values, GpuUInt128 modulus, GpuUInt128 primitiveRoot)
|
||||||
{
|
{
|
||||||
int n = (int)values.Length;
|
int n = (int)values.Length;
|
||||||
using var gpu = GpuContextPool.Rent();
|
var gpu = GpuContextPool.Rent();
|
||||||
var accelerator = gpu.Accelerator;
|
var accelerator = gpu.Accelerator;
|
||||||
var kernel = GetForwardKernel(accelerator);
|
var kernel = GetForwardKernel(accelerator);
|
||||||
var pool = ArrayPool<GpuUInt128>.Shared;
|
var pool = ArrayPool<GpuUInt128>.Shared;
|
||||||
var inputArray = pool.Rent(n);
|
var inputArray = pool.Rent(n);
|
||||||
var outputArray = pool.Rent(n);
|
var outputArray = pool.Rent(n);
|
||||||
values.CopyTo(inputArray);
|
values.CopyTo(inputArray);
|
||||||
using var inputBuffer = accelerator.Allocate1D<GpuUInt128>(n);
|
var inputBuffer = accelerator.Allocate1D<GpuUInt128>(n);
|
||||||
using var outputBuffer = accelerator.Allocate1D<GpuUInt128>(n);
|
var outputBuffer = accelerator.Allocate1D<GpuUInt128>(n);
|
||||||
inputBuffer.View.CopyFromCPU(ref inputArray[0], n);
|
inputBuffer.View.CopyFromCPU(ref inputArray[0], n);
|
||||||
UInt128 modValue = modulus;
|
UInt128 modValue = modulus;
|
||||||
UInt128 expBase = (modValue - 1UL) / (ulong)n;
|
UInt128 expBase = (modValue - 1UL) / (ulong)n;
|
||||||
@@ -883,6 +886,10 @@ public static class NttGpuMath
|
|||||||
outputArray.AsSpan(0, n).CopyTo(values);
|
outputArray.AsSpan(0, n).CopyTo(values);
|
||||||
pool.Return(inputArray, clearArray: true);
|
pool.Return(inputArray, clearArray: true);
|
||||||
pool.Return(outputArray, clearArray: true);
|
pool.Return(outputArray, clearArray: true);
|
||||||
|
outputBuffer.Dispose();
|
||||||
|
inputBuffer.Dispose();
|
||||||
|
gpu.Dispose();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Inverse(Span<GpuUInt128> values, GpuUInt128 modulus, GpuUInt128 primitiveRoot)
|
public static void Inverse(Span<GpuUInt128> values, GpuUInt128 modulus, GpuUInt128 primitiveRoot)
|
||||||
@@ -954,15 +961,15 @@ public static class NttGpuMath
|
|||||||
private static void InverseGpuReference(Span<GpuUInt128> values, GpuUInt128 modulus, GpuUInt128 primitiveRoot)
|
private static void InverseGpuReference(Span<GpuUInt128> values, GpuUInt128 modulus, GpuUInt128 primitiveRoot)
|
||||||
{
|
{
|
||||||
int n = values.Length;
|
int n = values.Length;
|
||||||
using var gpu = GpuContextPool.Rent();
|
var gpu = GpuContextPool.Rent();
|
||||||
var accelerator = gpu.Accelerator;
|
var accelerator = gpu.Accelerator;
|
||||||
var kernel = GetInverseKernel(accelerator);
|
var kernel = GetInverseKernel(accelerator);
|
||||||
var pool = ArrayPool<GpuUInt128>.Shared;
|
var pool = ArrayPool<GpuUInt128>.Shared;
|
||||||
var inputArray = pool.Rent(n);
|
var inputArray = pool.Rent(n);
|
||||||
var outputArray = pool.Rent(n);
|
var outputArray = pool.Rent(n);
|
||||||
values.CopyTo(inputArray);
|
values.CopyTo(inputArray);
|
||||||
using var inputBuffer = accelerator.Allocate1D<GpuUInt128>(n);
|
var inputBuffer = accelerator.Allocate1D<GpuUInt128>(n);
|
||||||
using var outputBuffer = accelerator.Allocate1D<GpuUInt128>(n);
|
var outputBuffer = accelerator.Allocate1D<GpuUInt128>(n);
|
||||||
inputBuffer.View.CopyFromCPU(ref inputArray[0], n);
|
inputBuffer.View.CopyFromCPU(ref inputArray[0], n);
|
||||||
UInt128 modValue = modulus;
|
UInt128 modValue = modulus;
|
||||||
UInt128 expBase = (modValue - 1UL) / (ulong)n;
|
UInt128 expBase = (modValue - 1UL) / (ulong)n;
|
||||||
@@ -993,30 +1000,40 @@ public static class NttGpuMath
|
|||||||
outputArray.AsSpan(0, n).CopyTo(values);
|
outputArray.AsSpan(0, n).CopyTo(values);
|
||||||
pool.Return(inputArray, clearArray: true);
|
pool.Return(inputArray, clearArray: true);
|
||||||
pool.Return(outputArray, clearArray: true);
|
pool.Return(outputArray, clearArray: true);
|
||||||
|
outputBuffer.Dispose();
|
||||||
|
inputBuffer.Dispose();
|
||||||
|
gpu.Dispose();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ForwardGpuStaged(Span<GpuUInt128> values, GpuUInt128 modulus, GpuUInt128 primitiveRoot)
|
private static void ForwardGpuStaged(Span<GpuUInt128> values, GpuUInt128 modulus, GpuUInt128 primitiveRoot)
|
||||||
{
|
{
|
||||||
int n = values.Length;
|
int n = values.Length;
|
||||||
using var gpu = GpuContextPool.Rent();
|
var gpu = GpuContextPool.Rent();
|
||||||
var accelerator = gpu.Accelerator;
|
var accelerator = gpu.Accelerator;
|
||||||
using var buffer = accelerator.Allocate1D<GpuUInt128>(n);
|
var buffer = accelerator.Allocate1D<GpuUInt128>(n);
|
||||||
buffer.View.CopyFromCPU(ref values[0], n);
|
buffer.View.CopyFromCPU(ref values[0], n);
|
||||||
var cache = GetSquareCache(accelerator, n, modulus, primitiveRoot);
|
var cache = GetSquareCache(accelerator, n, modulus, primitiveRoot);
|
||||||
ForwardDevice(accelerator, buffer.View, n, modulus, cache);
|
ForwardDevice(accelerator, buffer.View, n, modulus, cache);
|
||||||
buffer.View.CopyToCPU(ref values[0], n);
|
buffer.View.CopyToCPU(ref values[0], n);
|
||||||
|
buffer.Dispose();
|
||||||
|
gpu.Dispose();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void InverseGpuStaged(Span<GpuUInt128> values, GpuUInt128 modulus, GpuUInt128 primitiveRoot)
|
private static void InverseGpuStaged(Span<GpuUInt128> values, GpuUInt128 modulus, GpuUInt128 primitiveRoot)
|
||||||
{
|
{
|
||||||
int n = values.Length;
|
int n = values.Length;
|
||||||
using var gpu = GpuContextPool.Rent();
|
var gpu = GpuContextPool.Rent();
|
||||||
var accelerator = gpu.Accelerator;
|
var accelerator = gpu.Accelerator;
|
||||||
using var buffer = accelerator.Allocate1D<GpuUInt128>(n);
|
var buffer = accelerator.Allocate1D<GpuUInt128>(n);
|
||||||
buffer.View.CopyFromCPU(ref values[0], n);
|
buffer.View.CopyFromCPU(ref values[0], n);
|
||||||
var cache = GetSquareCache(accelerator, n, modulus, primitiveRoot);
|
var cache = GetSquareCache(accelerator, n, modulus, primitiveRoot);
|
||||||
InverseDevice(accelerator, buffer.View, n, modulus, cache);
|
InverseDevice(accelerator, buffer.View, n, modulus, cache);
|
||||||
buffer.View.CopyToCPU(ref values[0], n);
|
buffer.View.CopyToCPU(ref values[0], n);
|
||||||
|
buffer.Dispose();
|
||||||
|
gpu.Dispose();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ForwardDevice(Accelerator accelerator, ArrayView<GpuUInt128> data, int length, GpuUInt128 modulus, SquareCacheEntry cache)
|
private static void ForwardDevice(Accelerator accelerator, ArrayView<GpuUInt128> data, int length, GpuUInt128 modulus, SquareCacheEntry cache)
|
||||||
@@ -1221,7 +1238,7 @@ public static class NttGpuMath
|
|||||||
|
|
||||||
public static void PointwiseMultiply(Span<GpuUInt128> left, Span<GpuUInt128> right, GpuUInt128 modulus)
|
public static void PointwiseMultiply(Span<GpuUInt128> left, Span<GpuUInt128> right, GpuUInt128 modulus)
|
||||||
{
|
{
|
||||||
using var gpu = GpuContextPool.Rent();
|
var gpu = GpuContextPool.Rent();
|
||||||
var accelerator = gpu.Accelerator;
|
var accelerator = gpu.Accelerator;
|
||||||
var kernel = GetMulKernel(accelerator);
|
var kernel = GetMulKernel(accelerator);
|
||||||
var pool = ArrayPool<GpuUInt128>.Shared;
|
var pool = ArrayPool<GpuUInt128>.Shared;
|
||||||
@@ -1229,8 +1246,8 @@ public static class NttGpuMath
|
|||||||
var rightArray = pool.Rent(right.Length);
|
var rightArray = pool.Rent(right.Length);
|
||||||
left.CopyTo(leftArray);
|
left.CopyTo(leftArray);
|
||||||
right.CopyTo(rightArray);
|
right.CopyTo(rightArray);
|
||||||
using var leftBuffer = accelerator.Allocate1D<GpuUInt128>(left.Length);
|
var leftBuffer = accelerator.Allocate1D<GpuUInt128>(left.Length);
|
||||||
using var rightBuffer = accelerator.Allocate1D<GpuUInt128>(right.Length);
|
var rightBuffer = accelerator.Allocate1D<GpuUInt128>(right.Length);
|
||||||
leftBuffer.View.CopyFromCPU(ref leftArray[0], left.Length);
|
leftBuffer.View.CopyFromCPU(ref leftArray[0], left.Length);
|
||||||
rightBuffer.View.CopyFromCPU(ref rightArray[0], right.Length);
|
rightBuffer.View.CopyFromCPU(ref rightArray[0], right.Length);
|
||||||
kernel(left.Length, leftBuffer.View, rightBuffer.View, modulus);
|
kernel(left.Length, leftBuffer.View, rightBuffer.View, modulus);
|
||||||
@@ -1241,6 +1258,10 @@ public static class NttGpuMath
|
|||||||
rightArray.AsSpan(0, right.Length).CopyTo(right);
|
rightArray.AsSpan(0, right.Length).CopyTo(right);
|
||||||
pool.Return(leftArray, clearArray: true);
|
pool.Return(leftArray, clearArray: true);
|
||||||
pool.Return(rightArray, clearArray: true);
|
pool.Return(rightArray, clearArray: true);
|
||||||
|
rightBuffer.Dispose();
|
||||||
|
leftBuffer.Dispose();
|
||||||
|
gpu.Dispose();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ulong[] GenerateSmallPrimes(int limit)
|
private static ulong[] GenerateSmallPrimes(int limit)
|
||||||
|
|||||||
@@ -223,15 +223,15 @@ public class MersenneDivisorCycles
|
|||||||
int count = (int)Math.Min(batchSizeUL, maxDivisor), i, idx;
|
int count = (int)Math.Min(batchSizeUL, maxDivisor), i, idx;
|
||||||
ulong[] divisors, outCycles, validDivisors;
|
ulong[] divisors, outCycles, validDivisors;
|
||||||
|
|
||||||
divisors = pool.Rent(count);
|
divisors = pool.Rent(count);
|
||||||
outCycles = pool.Rent(count);
|
outCycles = pool.Rent(count);
|
||||||
using var lease = GpuKernelPool.GetKernel(useGpuOrder: true);
|
var lease = GpuKernelPool.GetKernel(useGpuOrder: true);
|
||||||
var accelerator = lease.Accelerator;
|
var accelerator = lease.Accelerator;
|
||||||
using var stream = accelerator.CreateStream();
|
var stream = accelerator.CreateStream();
|
||||||
var kernel = accelerator.LoadAutoGroupedStreamKernel<
|
var kernel = accelerator.LoadAutoGroupedStreamKernel<
|
||||||
Index1D,
|
Index1D,
|
||||||
ArrayView1D<ulong, Stride1D.Dense>,
|
ArrayView1D<ulong, Stride1D.Dense>,
|
||||||
ArrayView1D<ulong, Stride1D.Dense>>(GpuDivisorCycleKernel);
|
ArrayView1D<ulong, Stride1D.Dense>>(GpuDivisorCycleKernel);
|
||||||
|
|
||||||
|
|
||||||
using Stream outputStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read, BufferSize10M, useAsync: true);
|
using Stream outputStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read, BufferSize10M, useAsync: true);
|
||||||
@@ -309,12 +309,16 @@ public class MersenneDivisorCycles
|
|||||||
start = end + 1UL;
|
start = end + 1UL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
pool.Return(divisors, clearArray: false);
|
pool.Return(divisors, clearArray: false);
|
||||||
pool.Return(outCycles, clearArray: false);
|
pool.Return(outCycles, clearArray: false);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
stream.Dispose();
|
||||||
|
lease.Dispose();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
const byte ByteZero = 0;
|
const byte ByteZero = 0;
|
||||||
const byte ByteOne = 1;
|
const byte ByteOne = 1;
|
||||||
|
|||||||
@@ -141,20 +141,20 @@ public sealed class MersenneNumberTester(
|
|||||||
|
|
||||||
UInt128[] qs = qsBuffer;
|
UInt128[] qs = qsBuffer;
|
||||||
|
|
||||||
using var gpuLease = GpuKernelPool.GetKernel(_useGpuOrder);
|
var gpuLease = GpuKernelPool.GetKernel(_useGpuOrder);
|
||||||
var accelerator = gpuLease.Accelerator;
|
var accelerator = gpuLease.Accelerator;
|
||||||
var orderKernel = gpuLease.OrderKernel!;
|
var orderKernel = gpuLease.OrderKernel!;
|
||||||
|
|
||||||
// Guard long-running kernels by chunking the warm-up across batches.
|
// Guard long-running kernels by chunking the warm-up across batches.
|
||||||
// Reuse the same ScanBatchSize knob used for scanning.
|
// Reuse the same ScanBatchSize knob used for scanning.
|
||||||
int batchSize = GpuConstants.ScanBatchSize;
|
int batchSize = GpuConstants.ScanBatchSize;
|
||||||
ulong divMul = (ulong)((((UInt128)1 << 64) - 1UL) / exponent) + 1UL;
|
ulong divMul = (ulong)((((UInt128)1 << 64) - 1UL) / exponent) + 1UL;
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
while (offset < idx)
|
while (offset < idx)
|
||||||
{
|
{
|
||||||
int count = Math.Min(batchSize, idx - offset);
|
int count = Math.Min(batchSize, idx - offset);
|
||||||
using var qBuffer = accelerator.Allocate1D<PerfectNumbers.Core.Gpu.GpuUInt128>(count);
|
var qBuffer = accelerator.Allocate1D<PerfectNumbers.Core.Gpu.GpuUInt128>(count);
|
||||||
using var orderBuffer = accelerator.Allocate1D<ulong>(count);
|
var orderBuffer = accelerator.Allocate1D<ulong>(count);
|
||||||
// Convert to device-friendly GpuUInt128 on the fly
|
// Convert to device-friendly GpuUInt128 on the fly
|
||||||
var tmp = System.Buffers.ArrayPool<PerfectNumbers.Core.Gpu.GpuUInt128>.Shared.Rent(count);
|
var tmp = System.Buffers.ArrayPool<PerfectNumbers.Core.Gpu.GpuUInt128>.Shared.Rent(count);
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
@@ -167,25 +167,28 @@ public sealed class MersenneNumberTester(
|
|||||||
orderKernel(count, exponent, divMul, qBuffer.View, orderBuffer.View);
|
orderKernel(count, exponent, divMul, qBuffer.View, orderBuffer.View);
|
||||||
accelerator.Synchronize();
|
accelerator.Synchronize();
|
||||||
|
|
||||||
ulong[] orders = orderBuffer.GetAsArray1D();
|
ulong[] orders = orderBuffer.GetAsArray1D();
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
ulong order = orders[i];
|
ulong order = orders[i];
|
||||||
if (order == 0UL)
|
if (order == 0UL)
|
||||||
{
|
{
|
||||||
order = qs[offset + i].CalculateOrder();
|
order = qs[offset + i].CalculateOrder();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (useOrderCache)
|
if (useOrderCache)
|
||||||
{
|
{
|
||||||
OrderCache[qs[offset + i]] = order;
|
OrderCache[qs[offset + i]] = order;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
offset += count;
|
offset += count;
|
||||||
}
|
orderBuffer.Dispose();
|
||||||
|
qBuffer.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
ArrayPool<UInt128>.Shared.Return(qs);
|
gpuLease.Dispose();
|
||||||
|
ArrayPool<UInt128>.Shared.Return(qs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsMersennePrime(ulong exponent)
|
public bool IsMersennePrime(ulong exponent)
|
||||||
|
|||||||
@@ -81,8 +81,8 @@ public sealed class PrimeTester(bool useInternal = false)
|
|||||||
public static void IsPrimeBatchGpu(ReadOnlySpan<ulong> values, Span<byte> results)
|
public static void IsPrimeBatchGpu(ReadOnlySpan<ulong> values, Span<byte> results)
|
||||||
{
|
{
|
||||||
// Limit concurrency and declare variables outside loops for performance and reuse
|
// Limit concurrency and declare variables outside loops for performance and reuse
|
||||||
using var limiter = GpuPrimeWorkLimiter.Acquire();
|
var limiter = GpuPrimeWorkLimiter.Acquire();
|
||||||
using var gpu = GpuContextPool.Rent();
|
var gpu = GpuContextPool.Rent();
|
||||||
var accelerator = gpu.Accelerator;
|
var accelerator = gpu.Accelerator;
|
||||||
|
|
||||||
// Get per-accelerator cached kernel and device primes buffer.
|
// Get per-accelerator cached kernel and device primes buffer.
|
||||||
@@ -123,6 +123,8 @@ public sealed class PrimeTester(bool useInternal = false)
|
|||||||
|
|
||||||
ArrayPool<ulong>.Shared.Return(temp);
|
ArrayPool<ulong>.Shared.Return(temp);
|
||||||
state.ReturnScratch(scratch);
|
state.ReturnScratch(scratch);
|
||||||
|
gpu.Dispose();
|
||||||
|
limiter.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Per-accelerator GPU state for prime sieve (kernel + uploaded primes).
|
// Per-accelerator GPU state for prime sieve (kernel + uploaded primes).
|
||||||
@@ -283,13 +285,13 @@ public sealed class PrimeTester(bool useInternal = false)
|
|||||||
|
|
||||||
internal static void SharesFactorWithMaxExponentBatch(ReadOnlySpan<ulong> values, Span<byte> results)
|
internal static void SharesFactorWithMaxExponentBatch(ReadOnlySpan<ulong> values, Span<byte> results)
|
||||||
{
|
{
|
||||||
using var gpu = GpuContextPool.Rent();
|
var gpu = GpuContextPool.Rent();
|
||||||
var accelerator = gpu.Accelerator;
|
var accelerator = gpu.Accelerator;
|
||||||
var kernel = accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView<ulong>, ArrayView<byte>>(SharesFactorKernel);
|
var kernel = accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView<ulong>, ArrayView<byte>>(SharesFactorKernel);
|
||||||
|
|
||||||
int length = values.Length;
|
int length = values.Length;
|
||||||
using var inputBuffer = accelerator.Allocate1D<ulong>(length);
|
var inputBuffer = accelerator.Allocate1D<ulong>(length);
|
||||||
using var resultBuffer = accelerator.Allocate1D<byte>(length);
|
var resultBuffer = accelerator.Allocate1D<byte>(length);
|
||||||
|
|
||||||
ulong[] temp = ArrayPool<ulong>.Shared.Rent(length);
|
ulong[] temp = ArrayPool<ulong>.Shared.Rent(length);
|
||||||
values.CopyTo(temp);
|
values.CopyTo(temp);
|
||||||
@@ -298,6 +300,9 @@ public sealed class PrimeTester(bool useInternal = false)
|
|||||||
accelerator.Synchronize();
|
accelerator.Synchronize();
|
||||||
resultBuffer.View.CopyToCPU(ref results[0], length);
|
resultBuffer.View.CopyToCPU(ref results[0], length);
|
||||||
ArrayPool<ulong>.Shared.Return(temp);
|
ArrayPool<ulong>.Shared.Return(temp);
|
||||||
|
resultBuffer.Dispose();
|
||||||
|
inputBuffer.Dispose();
|
||||||
|
gpu.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
|||||||
Reference in new issue
Block a user